Baixe o app para aproveitar ainda mais
Prévia do material em texto
Capítulo 2 Fundamentos de Engenharia de Software para o Desenvolvimento de Software como Serviço através do uso de Metodologias Ágeis Regis Pires Magalhães, Francisco José Lins Magalhães, Nécio de Lima Veras, Thalisson Alves Oliveira e Polyanna Carvalho Moreira Abstract This chapter covers methodologies, languages, tools and artifacts carefully chosen to motivate students to exercise best practices in software development, supported by Software Engineering and Agile Methodologies to the construction of Software as a Service (SaaS). Concepts related to software architecture, testing, modularity and reuse are presented in theory and practice through analysis of a web application built for teaching purposes using Java language and Play Framework. Resumo Este capítulo aborda metodologias, linguagens, ferramentas e artefatos cuidadosamente selecionados para motivar os alunos a exercerem as melhores práticas de desenvolvimento de software, apoiadas na Engenharia de Software e em Metodologias Ágeis para a construção de Software como Serviço (SaaS). Conceitos relacionados à arquitetura de software, testes, modularidade e reuso são apresentados de forma teórica e prática através da análise de uma aplicação web construída para fins didáticos usando a linguagem Java e o Play Framework. 1.1. Introdução Sistemas computacionais estão presentes em toda parte no nosso cotidiano, desde nossos telefones até quando estamos em um voo entre continentes. Por meio do uso da internet, podemos complementar que os sistemas computacionais são acessíveis de qualquer lugar. Observando esse cenário é imperativo que esses sistemas possuam a qualidade intrínseca à sua importância. Nesse contexto, podemos fomentar a Engenharia de Software, que é uma disciplina da engenharia, cuja meta é o desenvolvimento de sistemas de software com boa relação custo benefício [Sommerville 2003]. A Engenharia de Software incorpora o conceito de Processos de Softwares, que está relacionado com práticas e artefatos para nortear o desenvolvimento de software com qualidade. Mas, geralmente esses processos (e. g. modelo em cascata e RUP) são muito onerosos, podendo elevar muito o tempo de finalização de um sistema. Esse fato abre lugar para as metodologias ágeis de desenvolvimento de software, pois estas pregam o desenvolvimento e entrega de pequenas partes do sistema com o incremento gradual das funcionalidades. O SCRUM representa uma dessas metodologias. Retornando ao fato dos sistemas serem acessíveis de todo lugar, desde a popularização da internet, existe uma convergência do desenvolvimento de software para este ambiente. Em meio a esse panorama, surge a computação em nuvem (Cloud Computing). Algumas empresas possuem uma poderosa infraestrutura de servidores e disponibilizam alguns serviços acessíveis através da internet. As principais classificações de serviços em nuvem são IaaS, PaaS e SaaS (Infrastructure as a Service, Plataform as a Service e Software as a Service, respectivamente). Na indústria de software moderna demanda-se o desenvolvimento de sistemas em menos tempo e com qualidade superior. Vislumbrando atender essas exigências podemos utilizar métodos ágeis para liberar versões de um software em menor tempo, focando em testes automatizados para ajudar na garantia da qualidade. Podemos também fazer uso de um leque de ferramentas que podem ajudar na execução do método ágil (e.g. ferramentas para controle de versão, IDE’s1 e frameworks de desenvolvimento). No âmbito dos sistemas web, temos a oportunidade de utilizar arquiteturas maduras como MVC (Model-View-Controller) e fazer implantação (deployment) das aplicações diretamente na nuvem. Nas seções posteriores serão detalhados alguns pontos acima citados, como processos de desenvolvimento, testes de software, SaaS, arquitetura MVC e computação em nuvem. Além disso, serão abordados conteúdos relativos à utilização de sistemas de controle de versão no processo de desenvolvimento de software e também implantação na infraestrutura de nuvem. 1.2. Processos de Desenvolvimento Qualquer projeto é formado por processos e estes são constituídos de atividades que, fazendo uso de ferramentas, técnicas e artefatos, são executados de forma organizada e/ou sincronizada. Um projeto é caracterizado por um tempo de vida finito e pela 1 Integrated Development Environment. Uma IDE facilita o desenvolvimento de um projeto de software. produção de um produto ou serviço. Existem produtos que são facilmente visualizados antes mesmo de sua construção, pois são quantificáveis, de escopo exato e incertezas mínimas como, por exemplo, construções prediais. Essa definição não representa o desenvolvimento de um software. É exatamente o contrário, pois este tipo de produto é intangível, de escopo com altas taxas de variações e incertezas constantes. Assim, um software por surgir de ideias conceituais, reajustáveis e não possuir recursos físicos, seu escopo pode variar, provocando mudanças sérias durante sua construção e dificultando sua visualização final. Esse fato de poder existir um grande número de possíveis estados torna o software um produto extremamente complexo, dificultando a elaboração de seu projeto de forma a atender todos os requisitos de qualidade e de controle total sobre os possíveis erros. Mas como obter um produto de software com qualidade diante de todas estas peculiaridades? Percebeu-se a necessidade de inclusão da disciplina de engenharia no desenvolvimento de software, pois com ela é possível que um gerente fortaleça práticas de gerenciamento para obtenção de um produto com alta qualidade. A Engenharia de Software aborda as formas de desenvolvimento e engloba três elementos fundamentais: métodos, ferramentas e procedimentos. Os métodos estão relacionados a um conjunto de tarefas que incluem planejamento, estimativas, projeto, codificação, testes e manutenção de sistemas. As ferramentas oferecem apoio aos envolvidos nos projeto e os procedimentos constituem a ligação entre os outros dois. Com isso, esses conjuntos de etapas são compreendidos como paradigmas da engenharia de software [Pressman 2005]. Um processo geral é um conjunto de passos parcialmente ordenados, constituídos por atividades, métodos, práticas e transformações com o objetivo de atingir alguma meta, detalhando: produto, etapas, agentes, insumos e resultados. Em processos que envolvem desenvolvimento de software podem ser definidas as seguintes atividades: desenvolvimento, manutenção, aquisição e contratação de software, além de também poderem existir subprocessos para cada um destes. Por exemplo, um processo de desenvolvimento abrange determinação dos requisitos, análise, desenho, implementação e testes [Paula Filho 2006]. Dessa forma, os processos para construção de um software são como conjunto de passos que irão trabalhar de forma ampla definições, desenvolvimento e manutenção. Existem diversos destes conjuntos que formam diferentes estratégias de abordagem e são denominados também de Modelos de Ciclo de Vida de Software [Pressman 2005]. Com isso abordaremos neste contexto os ciclos de vida de Waterfall, Espiral e Ágil. O modelo de Waterfall também conhecido como ciclo de vida clássico ou, ainda, modelo cascata, prega uma filosofia de sequência onde uma fase deve ser completa antes do início da próxima removendo assim muitos erros o mais cedo possível. É esperado nesta abordagem uma extensa documentação em cada fase para que informações importantes não sejam perdidas, caso um membro do projeto desmembre a equipe. Assim como também se uma nova pessoa for adicionada ao time, então esta poderá rapidamente participar de forma efetiva. Figura 1. Visão geral do modelo Waterfall [Pressman 2005]. O fluxo ilustrado pela figura 1 mostra as fases sequenciais previstas pelo modelo Waterfall. A longevidade do software é reconhecida pela fase de manutenção que repara os erros na medida em que são descobertos.Futuras versões do software são feitas usando as mesmas fases e consomem normalmente um prazo entre seis e dezoito meses. Este modelo pode funcionar bem quando usado com tarefas bem definidas como, por exemplo, voos espaciais da NASA, mas se torna problemático quando os clientes não possuem uma definição clara do que eles precisam [Fox e Patterson 2012]. Observou-se que esse problema é minimizado quando os clientes conseguem entender o que eles querem por meio da visualização de um protótipo e, ao mesmo tempo, os engenheiros entendem melhor como construir, uma vez que eles fizeram isso com a primeira interação com o cliente. Essa observação combinou protótipos de software com o modelo Waterfall e a ideia foi repetir uma sequência de quatro fases, onde cada uma resultaria em um protótipo mais aprimorado em relação à versão anterior [Boehm 1986 apud Fox e Patterson 2012]. Este modelo de ciclo de vida ganhou a denominação de Modelo Espiral. O Modelo Espiral é composto por quatro fases. A figura 2 ilustra como este ciclo de vida combina os modelos Waterfall e Prototipação. O processo se inicia no centro, com cada iteração ao redor da espiral executando as quatro fases e gerando como resultado um protótipo revisado. Isso se repete até que o produto esteja pronto para ser liberado ou lançado. Figura 2. Modelo Espiral [Fox e Patterson 2012]. Este modelo ao invés de produzir um documento com toda a documentação do projeto, constrói os documentos de requisitos, fundamentais para a evolução do projeto, por meio de cada iteração conforme as necessidades. Vale ressaltar que uma iteração envolve o cliente antes do produto ser finalizado, e isso reduz consideravelmente as chances de erros na concepção do sistema. Como as iterações demoram presumidamente entre seis e vinte e quatro meses, o cliente tem tempo hábil para pensar em novas ideias e isso seria um problema sério, pois os planejamentos deveriam ser revisados para transformar as novas sugestões em recursos do sistema. Ambos os modelos foram elencados porque envolvem um longo período de tempo e um volume muito grande de documentação e planejamento, bem como, fases maiores ainda emergindo o termo Big Design Up Front (BDUF). O desenvolvimento de software com a abordagem BDUF reflete que o planejamento é completado e aperfeiçoado antes mesmo de iniciar a codificação, o que praticamente inviabiliza uma mudança brusca de escopo [Fox e Patterson 2012]. Um grupo de desenvolvedores de software em fevereiro de 2001, chamado de Agile Alliance, começou a descobrir maneiras melhores e mais leves de desenvolver software, valorizando principalmente, pessoas e interações ao invés de processos e ferramentas, softwares funcionando no lugar de documentações abrangentes, colaborações com clientes do que negociações de contratos e respostas à mudanças por planos fechados. Esses valores deram origem ao Manifesto Ágil e possui ainda doze princípios que regem a filosofia de criar softwares com agilidade [Beck 2001]. Este modelo alternativo de desenvolvimento é baseado em mudanças abrangentes, como por exemplo um fato da vida. O desenvolvedor deve melhorar continuamente um protótipo incompleto, até que o cliente fique feliz com o resultado e, como o cliente oferecerá feedback a cada iteração, então a possibilidade de mal entendidos é consideravelmente reduzida. O modelo enfatiza algumas práticas para reduzir erros e aumentar a produtividade, tais como: Test-Driven Development (TDD), User Stories e Velocity. Contrastando com os outros dois modelo citados, o ciclo de vida Ágil é tão rápido que novas versões são disponibilizadas ao cliente a cada duas semanas e novos recursos são adicionados continuamente ao mesmo protótipo até que o cliente esteja satisfeito [Fox e Patterson 2012]. 1.3. Arquitetura Orientada a Serviço (SOA – Service Oriented Architecture) SOA é uma arquitetura de software onde todos os componentes são projetados para virarem serviços. Atualmente significa que os componentes de uma aplicação devem atuar como serviços interoperáveis e podem ser usados de forma independente e/ou recombinados com outras aplicações. Uma implementação que contrasta com isso é considerada um “software silo” e raramente possui uma API (Application Programming Interface) para seus componentes internos. Uma consequência do uso destes tipos de softwares são os custos para correção de erros, pois estes são muito menores em um aplicativo com SOA do que em um “software silo” [Fox e Patterson 2012]. Formada por componentes disponibilizados por meio de interfaces genéricas e protocolos padronizados, a SOA deve ser o mais independente possível dos sistemas que a consomem e de seu núcleo técnico de desenvolvimento, promovendo assim a reutilização e o aproveitamento de suas funcionalidades já existentes. Contudo, devemos ter muito cuidado para não confundir esta arquitetura com outras ideias que possuem certa semelhança, como por exemplo web services e padrões abertos para protocolos de comunicação e documentação [Serman 2010]. A Amazon iniciou em 1995 um site de varejo online como um software silo. Em meados de 2002 foi divulgado um e-mail enviado na época à todos os funcionários com as seguintes observações: ● Todos os times deverão expor seus dados e funcionalidades através de interfaces de serviços. ● Os times devem obrigatoriamente comunicar-se uns com os outros por meio desta interface. ● Lá não será permitido outra forma de comunicação. A única permitida é serviço de chamada de interface sob a rede. ● Não importa qual tecnologia será usada: HTTP, CORBA, PUBSUC, Protocolos personalizados, etc. ● Todos os serviços de interface, sem exceção, devem ser projetos para um ambiente externalizável. Isso quer dizer que o time deve planejar e projetar de forma que seja possível expor as interfaces para desenvolvedores do outro lado do mundo. Sem exceções. ● Quem não fizer isso será demitido. ● Obrigado. Tenham um ótimo dia! Este texto evidencia a necessidade da empresa em criar e usar serviços de rede para trocar informações. Em 2007, três anos depois da empresa colocar o produto online, surgiu um revolucionário software similar, o Facebook Plataform. Apoiado na SOA esta plataforma permite aos desenvolvedores criar aplicativos que interajam com o núcleo de funcionalidades do Facebook e extrair informações tais como: o que as pessoas gostam, quem são os seus amigos, quem está marcando suas fotos, entre outras. No mesmo contexto de redes sociais e, um exemplo contrastante, o Google+ usando um software silo foi lançado sem o uso de uma API própria. No entanto, três meses depois o produto foi atualizado com uma API bem mais poderosa, harmonizando com o que os usuários da marca Google estão habituados a usarem [Fox e Patterson 2012]. Objetivando um entendimento mais apurado sobre SOA, imagine um exemplo no qual iremos construir um serviço de uma livraria que irá conter três subsistemas: comentários (reviews), perfil de usuário (user profile) e, obviamente, compras (buying). A figura 3 mostra a arquitetura para um software silo. Figura 3. Modelo de software silo para serviços de uma livraria [Fox e Patterson 2012]. O silo forma internamente subsistemas que podem compartilhar acessos a dados diretamente nos diferentes subsistemas. Perceba que todos os subsistemas estão contidos em uma API externa única. Com isso, o subsistema de comentários pode acessar informações fora do seu contexto de forma direta, como por exemplo no subsistema de perfis de usuários. Já a figura 4 exibe o mesmo sistema, mas agora com a versão SOA, onde todos os subsistemas são separadas e independentes. Figura 4. Modelo SOA para serviços de uma livraria [Fox e Patterson 2012]. Notamos agora que se o subsistema de comentários necessitar de informações de um usuário, então ele não poderá recuperá-la diretamente na base de dados dos usuários e para isso ele deverá usar o serviço da API.Essa é exatamente a diferença crítica entre os dois modos. Notamos com isso que a SOA possibilita várias fatias verticais com diversas camadas e cada uma das fatias está conectada por meio de serviços, proporcionando bastante reusabilidade. 1.4. Computação em Nuvem SOA está nos fundamentos dos serviços providos através de computação em nuvem e é importante ter isso sempre em mente durante a implementação desses serviços, a fim de maximizar o aproveitamento dos seus benefícios. A computação em nuvem provê a infra-estrutura computacional escalável e confiável de hardware e de armazenamento, que deve necessariamente ser constituída de: (i) Comunicação realizada através da Internet para permitir que os clientes interajam com os serviços; (ii) Escalabilidade para lidar com flutuações na demanda, atendendo rapidamente ao crescimento do número de usuários; (iii) Confiabilidade para que o serviço e a comunicação estejam continuamente disponíveis. Inicialmente os serviços eram providos por servidores de custo elevado por serem mais confiáveis e por ser mais fácil lidar com poucos servidores do que com muitos computadores com menos recursos. No entanto, o advento dos clusters permitiu que computadores de baixo custo fossem interligados para oferecer as seguintes vantagens em relação ao uso de servidores de custo elevado: (i) clusters são mais escaláveis, podendo atualmente interligar até centenas de milhares de computadores; (ii) a distribuição de software em um cluster é facilitada pelo uso de máquinas virtuais que imitam um computador real, ao ponto de possibilitar a execução de outras instâncias de sistemas operacionais dentro do sistema hospedeiro. [Hoelzle e Barroso 2009] demonstraram que o custo de processadores, memória e armazenamento em clusters é cerca de 20 vezes menor que a quantidade equivalente em servidores de custo elevado. (iii) Embora os componentes de cluster sejam individualmente menos confiáveis que servidores e dispositivos de armazenamento de alto custo, a infra-estrutura de cluster torna o sistema mais confiável, devido ao uso extensivo de redundância. O custo total de cluster também é comparativamente menor devido ao baixo custo do hardware. Além disso, os serviços estão espalhados por datacenters distribuídos geograficamente para que até mesmo a ocorrência de um desastre natural não venha a tornar o serviço totalmente indisponível. Os custos por máquina e de pessoal dos grandes datacenters são substancialmente menores que os custos de pequenos datacenters, devido à economia de escala pela compra, operação e gerenciamento de centenas de milhares de computadores. O nível de aproveitamento do poder computacional de cada máquina também é superior, graças ao melhor compartilhamento dos recursos. [Hoelzle e Barroso 2009] apontam que pequenos datacenters utilizam somente cerca de 10% a 20% do total de seus recursos computacionais. Para melhorar esse cenário, os provedores passaram a disponibilizar recursos pagos pelo uso (pay-as-you-go). Assim, os usuários dos serviços pagam apenas pelos recursos que recebem, à semelhança do que ocorre com os serviços de distribuição de água, energia e telefonia que usamos em nosso dia a dia. Esse serviço de nuvem pública capaz de oferecer poder de processamento, armazenamento e comunicação a centavos por hora passou a ser chamado de Utility Computing [Armbrust et al. 2010]. O objetivo da Utility Computing é fornecer os componentes básicos como armazenamento, CPUs e largura de banda de uma rede como uma “mercadoria”, através de provedores especializados com um baixo custo por unidade utilizada [Sousa et al. 2010]. Usuários de serviços baseados em Utility Computing não precisam se preocupar com escalabilidade, pois a capacidade de armazenamento fornecido é praticamente infinita. A Utility Computing propõe fornecer disponibilidade total, isto é, os usuários podem ler e gravar dados a qualquer momento, sem serem bloqueados; os tempos de resposta são praticamente constantes e não dependem do número de usuários simultâneos, do volume de dados utilizado ou de parâmetros do sistema. Os usuários não precisam se preocupar com backups. Se os componentes falharem, é de responsabilidade do provedor substituí-los e tornar os dados disponíveis em tempo hábil através de réplicas [Brantner et al. 2008]. Desse modo, qualquer pessoa com uma boa ideia e algum conhecimento pode iniciar uma empresa de desenvolvimento de serviços em nuvem que podem atender bem milhões de clientes sem a mínima necessidade de construir ou mesmo operar um datacenter. O jogo social FarmVille2 obteve um milhão de jogadores em seus primeiros quatro dias e 75 milhões de jogadores mensais após 9 meses. Isso foi possível graças ao uso de Utility Computing provido pelo serviço Amazon Elastic Compute Cloud (EC2)3. Google App Engine4 e Microsoft Azure5 também se destacam como serviços populares de Utility Computing. Ambientes de computação em nuvem são tipicamente compostos por três modelos de serviços que definem um padrão arquitetural para soluções de computação em nuvem. Os modelos de serviços estão representados na figura 5 e são os seguintes: Software como Serviço (SaaS – Software as a Service), Plataforma como Serviço (PaaS – Platform as a Service) e Infra-estrutura como Serviço (IaaS – Infrastructure as a Service). Como este capítulo trata especificamente sobre o desenvolvimento de Software como Serviço, vamos explicar esse modelo de forma mais detalhada na próxima seção. Antes disso, porém, abordaremos resumidamente os modelos de PaaS e IaaS conforme descrito em [Sousa et. al. 2010]. Figura 5. Modelos de Serviços. 2 http://www.farmville.com/ 3 http://aws.amazon.com/ec2/ 4 http://developers.google.com/appengine/ 5 http://www.windowsazure.com/ O modelo de PaaS fornece um sistema operacional, linguagens de programação e ambientes de desenvolvimento para as aplicações, auxiliando a implementação de softwares, já que contém ferramentas de desenvolvimento e colaboração entre desenvolvedores. O usuário não administra ou controla a infraestrutura subjacente, mas tem controle sobre as aplicações implantadas e, possivelmente, sobre as configurações de aplicações hospedadas nesta infra-estrutura. Heroku6, Google App Engine7 e Aneka8 são exemplos de PaaS. O modelo de IaaS torna mais fácil e acessível o fornecimento de recursos, tais como servidores, rede, armazenamento e outros recursos de computação fundamentais para construir um ambiente de aplicação sob demanda, que podem incluir sistemas operacionais e aplicativos. Em geral, o usuário não administra ou controla a infra- estrutura da nuvem, mas tem controle sobre os sistemas operacionais, armazenamento e aplicativos implantados. Os recursos disponibilizados pela IaaS são geralmente virtualizados. O Amazon Elastic Cloud Computing (EC2)9 e o Elastic Utility Computing Architecture Linking Your Programs To Useful Systems (Eucalyptus)10 [Liu et al. 2007] são exemplos de IaaS. 1.5. Software como Serviço (SaaS) O modelo de SaaS fornece aos usuários softwares e dados com propósitos específicos através da Internet. Tais softwares são acessíveis a partir de vários dispositivos por meio de uma interface leve que normalmente é um navegador Web executado localmente no dispositivo cliente. Esse modelo diferencia-se da abordagem tradicional que exige a instalação e execução completa de um código binário na máquina cliente. No modelo de SaaS o usuário não administra ou controla a infra-estrutura subjacente que inclui rede, servidores, sistemas operacionais e dispositivos de armazenamento. Isso possibilita que os desenvolvedores foquem em inovação e não na infra-estrutura, o que melhora a produtividade e agiliza o desenvolvimento [Sousa et. al. 2009]. O software disponibilizado como serviço através da Web pode ser acessado pelos usuários de qualquer lugar e a qualquer momento. Além disso, suas atualizações podem ocorrer de forma transparente para os usuários,sem a necessidade de realizar download, instalação e execução de novas versões na máquina cliente. Como exemplos de SaaS, podemos citar aplicações Web relacionadas a busca, redes sociais e vídeos. A seguir são listadas algumas vantagens do uso de SaaS para usuários e desenvolvedores [Fox e Patterson 2012]: ● Desde que os usuários não precisam instalar a aplicação, eles não precisam se preocupar com requisitos específicos de hardware ou de sistema operacional; ● Os dados relacionados a determinado serviço são armazenamentos e gerenciados pelo próprio serviço. Assim, os usuários não precisam fazer backup dos dados ou correr o risco de perda de dados por problemas com o hardware ou mesmo devido ao roubo do dispositivo. 6 http://www.heroku.com/ 7 https://developers.google.com/appengine/ 8 http://www.manjrasoft.com/products.html 9 http://aws.amazon.com/ec2/ 10 http://www.eucalyptus.com/ ● SaaS naturalmente fornece um ambiente propício ao compartilhamento, edição e manipulação coletiva dos dados. ● O software servidor é executado em um ambiente com hardware e sistema operacional controlados e selecionados pelo desenvolvedor, evitando problemas de compatibilidade relacionadas à instalação de software em uma grande variedade de computadores e sistemas operacionais. Além disso, é possível disponibilizar novas versões da aplicação apenas para um grupo restrito de usuários que podem testá-la para descobrir potenciais problemas antes de uma disponibilização mais ampla que afetaria a maioria dos usuários. ● O uso de um ambiente controlado para execução de SaaS possibilita a realização de atualizações mais frequentes de software e hardware. A possibilidade de atualizações frequentes alinha-se perfeitamente ao ciclo de vida de softwares desenvolvidos através de metodologias ágeis. Assim, novos recursos podem ser disponibilizados regularmente para evitar que os usuários migrem para serviços concorrentes. Além disso, evita a pirataria ou cópia ilegal do software, já que o usuário usa a aplicação remotamente e não tem acesso ao código que está sendo executado. ● Possibilidade de cobrar um valor periódico ou baseado na demanda de uso do software. Essas vantagens explicam o motivo do rápido crescimento de SaaS e também porque estão sendo desenvolvidas versões SaaS para softwares tradicionais. Um exemplo disso é a versão SaaS dos populares aplicativos de escritório Word, Excel e PowerPoint da Microsoft (Microsoft Office 365)11. No entanto, aplicações desenvolvidas como SaaS requerem acesso à Internet, o que pode restringir seu uso em determinadas situações. Para atenuar esse problema, algumas aplicações SaaS têm possibilitado a alternativa de permitir sua execução offline, o que, por outro lado, aumenta a complexidade do desenvolvimento, por exigir um certo controle sobre o que está sendo manipulado na máquina cliente e que precisará ser posteriormente sincronizado com a versão online, assim que isso for possível. Vários frameworks voltados para programação Web permitem o desenvolvimento de SaaS. Neste capítulo ilustramos os conceitos abordados através de exemplos implementados usando o Play Framework12, que foi concebido no intuito de facilitar o desenvolvimento através do uso de metodologias Ágeis. Isso ocorre porque ele se alinha ao ciclo de vida ágil. Além disso, o framework permite que a codificação seja realizada na amplamente difundida linguagem Java, tendo como pré-requisito para criação das primeiras aplicações Web, apenas o conhecimento do Java SE (Standard Edition) e da arquitetura Modelo-Visão-Controlador (MVC). A baixa curva de aprendizagem torna o framework propício para ilustrar os conceitos de engenharia de software para o desenvolvimento de SaaS. Além disso, as aplicações implementadas a partir deste framework podem ser facilmente disponibilizadas em modelos de Plataforma como Serviço (PaaS), como o Google App Engine13 e o Heroku14. Também é possível disponibilizá-las no modelo de Infra-estrutura como Serviço (IaaS), usando o serviço Amazon Elastic Cloud Computing (EC2), por exemplo. 11 http://www.office365.com/ 12 http://www.playframework.org/ 13 http://appengine.google.com/ 14 http://www.heroku.com/ Esta seção mostrou como SaaS tem causado alterações substanciais em relação ao desenvolvimento tradicional de software. A seção a seguir trata da arquitetura Modelo-Visão-Controlador que é amplamente difundida em aplicações de SaaS. 1.6. Arquitetura Modelo-Visão-Controlador (MVC – Model-View-Controller) O padrão de arquitetura MVC – Modelo-Visão-Controlador – é amplamente difundido em aplicações Web. A ideia original dessa arquitetura surgiu em 1978 durante a visita de Trygve Reenskaug a uma equipe de desenvolvimento da Xerox, que terminou implementando o MVC na linguagem Smalltalk [Liu 1996]. A arquitetura MVC divide os componentes necessários para construir uma aplicação em três tipos, garantindo uma clara separação de papéis: ● um modelo de dados (model) ou objeto de aplicação que não contém código de apresentação; ● um objeto de visão (view), responsável pela exibição do modelo de dados; ● um objeto de controle (controller) que reage às entradas do usuário, atualizando o modelo de dados. Algumas razões para o sucesso da arquitetura MVC estão ligados a legibilidade, modularidade e separação de papéis. Sistemas construídos com uso da abordagem MVC tendem a ser flexíveis e extensíveis. A separação de papéis permite um desenvolvimento mais organizado da aplicação, onde alterações na apresentação dos dados não implicam em mudanças na forma como os dados são manipulados e vice- versa. Desde que a apresentação fica separada da lógica, alterações significativas na apresentação não afetam seu comportamento, sendo inclusive possível substituir uma tecnologia de visão por outra. Desse modo, é possível desenvolver, editar e testar cada parte da aplicação separadamente e com mais eficiência. 1.6.1. Modelo A camada de modelo contem a lógica da aplicação e representa especificamente as informações que serão apresentadas em formulários da camada de visão com que a aplicação trabalha. A maioria das aplicações usa um mecanismo de armazenamento de dados permanente, como um banco de dados, para guardar e recuperar as informações necessárias à camada de modelo, apresentando também as anotações JPA para a manipulação desses mesmos dados. A Figura 6 apresenta um modelo chamado Pessoa, que permite o acesso a dados de uma tabela de nome pessoas. package models; import java.util.Date; import javax.persistence.*; import play.data.validation.Required; import play.db.jpa.*; @Entity(name="pessoas") public class Pessoa extends Model { @Column(length=50) @Required public String nome; @Column(length=10) public String fone; @Temporal(TemporalType.DATE) @Column(name="dt_nasc") public Date dtNasc; @Override public String toString() { return nome + " - " + fone + " - " + dtNasc; } } Figura 6. Modelo Pessoa (app/models/Pessoa.java) Essa camada é responsável pelo acesso a banco de dados, deixando as informações prontas, o controlador requisita essas informações levando-as para a camada de visão, onde serão exibidas na template correta. O modelo não possui conhecimento de quais serão as interfaces com usuário que serão utilizadas. Recomenda-se como boa prática de programação relativa à arquitetura MVC, que os controladores possuam pouco código e que os modelos possam ter códigos maiores [Chelimsky et al. 2010]. A responsabilidade do controlador é somente a de receber entradas e fazer chamadas ao modelo para obter os dados que preencherão a visão. Assim, o controlador basicamente fica responsável apenas por instanciar algumas classes, obter dados dos modelos e enviá-los à visão adequada. Por outro lado, os modelos realizam manipulação, validação e filtragem de dados. 1.6.2. Rotas, Controladores e REST De acordo com a arquitetura MVC, modelos e visões não devem se comunicar diretamente. Os controladoresfuncionam como intermediários ou elos de ligação entre modelos e visões. Um controlador recebe as requisições HTTP endereçadas a ele, obtém e/ou manipula os dados de um ou mais modelos, preenche uma determinada visão com os dados obtidos e retorna uma resposta para o cliente, resultante da visão preenchida. No Play Framework, o controlador corresponde a uma classe, onde cada método geralmente é a uma ação responsável pela interação entre modelos e visões. A Figura 7 apresenta um controlador de nome Application, constituído por duas ações (index e show). Cada uma das ações obtém dados do modelo Pessoa e usa esse dados para preencher as visões index e show, respectivamente. package controllers; import play.*; import play.data.validation.Valid; import play.mvc.*; import java.util.*; import models.*; public class Application extends Controller { public static void index(String nome) { List<Pessoa> pessoas = Pessoa.findAll(); render(pessoas); } public static void show(long id) { Pessoa p = Pessoa.findById(id); render(p); } } Figura 7. Controlador Application (app/controllers/Application.java) Cada requisição HTTP enviada ao servidor Web possui uma URI que é usada para identificar o servidor Web, o controlador e a ação a ser executada pelo controlador. Além disso, a URI ainda pode possuir parâmetros a serem usados pelo controlador. As relações entre URIs e quais são os controladores e as ações que estão associados a elas são determinadas por um mecanismo de roteamento. Esse roteamento baseia-se em um conjunto de regras que são chamadas de rotas. No Play Framework é possível consultar e modificar as rotas através do arquivo conf/routes. Cada rota inicia com um método HTTP, seguido por um padrão de URI e pela definição da chamada de um método (action) do controlador. A Figura 8 apresenta um arquivo de rotas usado no Play Framework. # Routes # Home page GET / Application.index GET /pessoa/{id} Application.show({id}) # Map static resources from the /app/public folder to the /public path GET /public/ staticDir:public # Catch all * /{controller}/{action} {controller}.{action} Figura 8. Arquivo conf/routes A seguir, mostramos um exemplo de URI para exibir informações sobre a pessoa cujo id é 1: http://localhost:9000/pessoa/1. O número 1 da URI corresponde ao {id} da regra “GET /pessoa/{id} Application.show({id})” Ainda sobre a figura 8, podemos notar que cada rota consiste em três blocos de informações: O método HTTP; Padrão URI; Definição de chamada. ● O método HTTP pode ser qualquer método válido e suportado pelo protocolo HTTP, como por exemplo: GET, POST, PUT e DELETE; ● Uma URI define o endereço de solicitação da rota, podendo ter ou não parâmetros passados pela URL. Essas partes dinâmicas são variáveis provindas do controlador, onde cada parte dinâmica deve ser escrita entre chaves {...} ● As definições de chamadas constituem a última parte da rota, sendo compostas pelo nome do controlador e da ação a ser executada. Em última instância, há o REST (Representational State Transfer) [Fielding 2000], ou em português, Transferência de Estado Representacional, que descreve uma arquitetura de software para aplicações WEB que requisitam e manipulam recursos WEB, usando os métodos do protocolo HTTP já citados acima. Cada recurso REST é uma entidade acessível a partir de uma URL que oferece interação via HTTP, onde os recursos podem ser apresentados em diferentes formatos, como HTML, RSS, XML, PDF, etc. Dependendo exclusivamente da URL requisitada pelo cliente. REST afirma alguns princípios chave de desenvolvimento: ● A funcionalidade da aplicação é divida em recursos. ● Cada recurso é endereçado unicamente usando URIs. ● Todos os recursos partilham uma interface uniforme para a transferência de estado entre cliente e recurso. Se uma aplicação segue os princípios de desenvolvimento REST, a aplicação é denominada RESTful e passa a possuir URLs limpas, desde que a simples identificação do recurso na URI, juntamente com o método HTTP usado na requisição, são suficientes para determinar que ação deve ser tomada sobre o recurso. Twitter, Facebook, Foursquare e muitos outros serviços utilizam REST. Webservices têm ganhado cada vez mais atenção, não apenas pelo seu grande uso na criação de APIs, mas também por causa da simplicidade de consumir e publicar um serviço RESTful [Pautasso et al. 2008]. 1.6.3. Visões Uma visão é um componente usado para exibir dados de um modelo. Uma visão não deveria realizar lógica de negócio ou obter dados além dos disponíveis no modelo. Assim, múltiplas visões podem representar o mesmo modelo, sem interferir no comportamento da aplicação. Um exemplo disso seria a existência de duas visões para os mesmos dados: uma delas apresentando-os de forma tabular e a outra visão mostrando uma representação gráfica dos mesmos dados. A visão não deve fazer manipulação ou recuperação de dados, como por exemplo interações com o Banco de Dados. Ao invés disso, deve meramente exibir dados de um ou mais modelos. Por outro lado, a visão realiza a lógica de apresentação, que é bem diferente de lógica de controle e de negócio. Um exemplo de lógica de apresentação é o uso da cor vermelha para visualização de valores numéricos, caso eles sejam negativos. A visão é constituída por alguma tecnologia que permita a geração ou visualização da interface com o usuário. Uma dessas tecnologias consiste no uso de templates, associado a uma linguagem simples para manipulação e preenchimento adequado das templates. Diversos frameworks voltados para o desenvolvimento Web, inclusive o Play Framework, usam templates para a construção de visões. Uma template é um arquivo texto, onde são escritos os códigos em HTML que irão constituir o corpo da página na WEB, como também os elementos dinâmicos da template. Esss elementos normalmente são parâmetros ou variáveis fornecidos pelo controlador. Exemplo de um uma visão em que é possível fazer uma listagem: #{extends 'main.html' /} #{set title:'Contatos - Listagem' /} <table> <tr> <th>Nome</th> <th>Telefone</th> <th>Data de Nascimento</th> </tr> #{list pessoas, as:'p'} <tr> <td>${p.nome}</td> <td>${p.fone}</td> <td>${p.dtNasc}</td> </tr> #{/list} </table> Figura 9. Visão app/views/Application/index.html Perceba que na figura 9, a lógica da aplicação não se encontra na visão, encontramos na visão apenas o manuseio dos dados de forma a facilitar uma visualização. No início da visão é colocado o layout em que essa visão se encontra, é possível também colocarmos o título para a página. É importante ressaltar que as visões devem ser implementadas de modo a possibilitar boa visualização em diferentes dispositivos. #{extends 'main.html' /} #{set title:'Contatos - Visualização' /} <p>Nome: ${p.nome}</p> <p>Telefone: ${p.fone}</p> <p>Data de Nascimento: ${p.dtNasc}</p> Figura 10. Visão app/views/Application/show.html Na figura 10, temos uma visualização simples de um contato, nesta visão temos que o id do contato foi passado como parâmetro pela URL e então temos o objeto Contato na variável p e então seus dados podem ser acessados como no exemplo. 1.7. Testes A grande maioria das pessoas já teve alguma experiência com um software que não funcionou como esperado. Softwares que não funcionam corretamente podem levar a muitos problemas, incluindo financeiro, tempo e reputação das empresas. Podendo, inclusive, chegar a influenciar na integridade das pessoas [ISTQB 2011]. Dado esse fato, podemos associar a qualidade de um software à quantidade de falhas percebidas no mesmo. O teste de software ajuda a medir essa qualidade no momento em que julgamos que as funcionalidades testadas estão funcionando como requisitadas. Assim, podemos dividir os testes em quatro níveis [ISTQB 2011]: ● Testede Componente (ou de unidade) ○ Teste de componentes ou unidades do código que podem ser testados separadamente (e. g. métodos de uma classe). ● Teste de Integração ○ Teste de interface entre componentes (e. g. interações de diferentes partes do sistema, como cadastro e financeiro). ● Teste de Sistema ○ Teste do comportamento de todo o sistema. ● Teste de Aceite ○ Normalmente verifica se o sistema está apropriado para o uso por um usuário com perfil de negócio. Para testar um software podemos fazê-lo de dois modos: manual, como por exemplo usar o sistema e analisar se as funcionalidades atendem aos requisitos, inspecionar visualmente o código para avaliar se ele faz o que se propõe a fazer; ou automático, como realizar asserções nas funções do código, inserindo uma entrada conhecida e verificando se a saída esperada ocorre, como mostra a Figura 11. Atualmente podemos contar com ferramentas e APIs que ajudam na automação de testes como JUnit15 e Selenium16. Figura 11. Estrutura de uma classe de teste usando o framework JUnit (http:// www.devmedia.com.br/imagens/javamagazine/mpjuiiujfig10.jpg) É importante ressaltar que pesquisas revelam que 58% de bugs em software resultam de problemas com infra-estrutura de testes e processos, e não de falhas de projeto. Elas apontam também que ambientes em que os testes são completamente automatizados ainda são raros e, inclusive, existem locais em que a totalidade dos testes é feita de maneira manual [Fox e Patterson 2012]. Estimamos que isso ocorra pelo simples fato de que testar é muito caro em relação ao tempo, podendo tomar mais de 50% do prazo do projeto. Para incentivar a cultura de testes automatizados de software e garantia de qualidade, nasceram abordagens como o TDD (Testing-Driven Development) e BDD (Behavior-Driven Design). Em uma tradução livre, TDD seria Desenvolvimento dirigido por testes e BDD Projeto guiado por comportamento. O TDD é caracterizado pelos seguintes passos: ● Os testes relativos à determinadas características são escritos antes mesmo da funcionalidade estar codificada. Neste momento os testes irão falhar. ● O código é construído de modo a fazer todos os testes executarem com sucesso, mesmo que não seja feito da maneira mais correta e completa. ● Feito isso, objetivando transformar o código em algo mais legível, padronizado e completo, é feita uma refatoração e os testes devem continuar executando sem erros. 15 http://junit.org/ 16 http://seleniumhq.org/ ● Todo o processo é repetido com outra funcionalidade ou, simplesmente, adicionam-se mais testes. Para exemplificar o TDD, imaginemos a implementação de uma funcionalidade que receba dois números e retorne a soma deles. Seguindo os passos acima, criaríamos a classe CalculoTest e também o método de teste testExecutaCalculo, que invoca a funcionalidade executaCalculo da classe Calculo. Passaríamos como parâmetro os números 10 e 5 e esperaríamos que o retorno fosse 15. Passaríamos também os parâmetros 11 e 10 para esperarmos o número 21 como resposta. Como inicialmente este método retornaria sempre zero, então ao executarmos o teste, este falharia. O próximo passo é implementar o código de forma que esses testes não falhem. Após isso podemos refatorar o método executaCalculo para que fique o mais legível possível. Os testes devem continuar funcionando e, por fim, ou adicionaríamos mais testes com outros parâmetros, ou criaríamos uma nova funcionalidade. Vale frisar que todo o processo é repetido até que todas as unidades de código sejam consideradas como testadas. Direcionando agora para o BDD podemos fazer as seguintes considerações [Fox e Patterson 2012]: ● BDD faz perguntas sobre comportamentos antes e durante o desenvolvimento, visando reduzir falhas na comunicação dentro do projeto. ● Requisitos são escritos como estórias de usuários. São criadas descrições simples de como a aplicação deve ser utilizada. ● BDD se concentra no comportamento da aplicação versus a implementação da aplicação e os testes são conduzidos utilizando TDD. Conforme considerado acima, as estórias de usuário passam a ser representadas como cenários e compõem um texto atendendo a tripla “Dado que, Quando e Então”. Desse modo, as máquinas também podem compreender esse texto que se aproxima da linguagem natural. Um exemplo simples: suponha que você tenha escolhido uma estória que determinado programa deve receber dois números e somá-los. Assim, você pode representar essa funcionalidade gerando a tripla: ● Dado que: eu recebo dois números. ● Quando: eu executar o programa. ● Então: os números são somados e retorna o resultado. Com isso, podemos representar as estórias de usuário obedecendo a prescrição acima e usamos essa informação para homologar as funcionalidades frente ao cliente. Além disso, os testes ainda serão automatizados, pois essa informação será lida e verificada automaticamente com os resultados. 1.8. Implantação (Deploy) da Aplicação Ao trabalhar com desenvolvimento de software, é importante dividir as etapas de trabalho. Mesmo em processos ágeis, algumas etapas podem ser reconhecidas, como a etapa de desenvolvimento, que é momento em que o software está sendo construído. Outra etapa é a de testes. Finalmente, também há um momento em que, após implmentadas as funcionalidades da iteração, a aplicação é posta em produção e o cliente pode usá-las e avaliá-las. Esse momento pode ser chamado de implantação do software, que ocorre após a aplicação ter sido diversas vezes testada e, depois, colocada em um ambiente no qual o stakeholder poderá utilizar. O processo de implantação (deploy em inglês) é todo o conjunto de atividades necessárias para que o software esteja disponível para o cliente. O momento para a realização desse processo, vai depender dos acordos feitos entre o desenvolvedor e o cliente. Há basicamente três ambientes utilizados pela comunidade: homologação (teste), desenvolvimento e produção, conforme descrito a seguir. Desenvolvimento: ambiente onde a aplicação é desenvolvida. Podendo ser executado localmente na máquina do desenvolvedor, por exemplo. Homologação: é o ambiente em que a aplicação pode ser testada. O desenvolvedor irá produzir o software no ambiente de desenvolvimento, e depois irá testá-lo no ambiente de homologação. Produção: Local em que o cliente pode ver o sistema funcionando, neste ambiente tudo que está nele já deve ter sido desenvolvido e testado. É o ambiente em que o usuário irá poder utilizar a aplicação. O ideal é que os ambientes devam ser semelhantes quanto à configuração das máquinas, pois a aplicação será executada em todos eles. A execução em cada um desses ambientes no momento oportuno poderá ser feita por uma pessoa responsável, pois os ambientes podem possuir um certo grau de complexidade quanto às configurações, requerendo um profissional devidamente capacitado para operá-los. Convém que os ambientes sejam fisicamente separados, pois as atividades de desenvolvimento podem ocasionar problemas operacionais no sistema. Deve-se cuidar também para evitar que códigos não testados sejam colocados em ambientes de produção. Uma das características de grande parte dos frameworks Web é possuir ambientes de desenvolvimento distintos para possibilitar a personalização ou configuração de cada um deles. No que diz respeito ao Play framework, pode-se configurar cada um desses ambientes de desenvolvimento. A implantação de uma aplicação de SaaS implementada no Play poderia ser realizada na PaaS Heroku, por exemplo. A utilização de serviços como esse possibilita a implantação e execução da aplicação em nuvem, além de manter um registro (log) do que está acontecendo e outras funcionalidades. Também é uma boa prática a utilização de serviços de integração contínua. Com eles, cada commit no servidor de integração contínua realiza um build da aplicação e executa todos os testes, tendo como grande vantagem o feedback instantâneo. Dessemodo, erros introduzidos por diferentes desenvolvedores ao longo do processo podem ser corrigidos rapidamente pela equipe. Não é preciso ter o trabalho de configurar banco de dados e refazer configurações a cada vez que for necessário executar a aplicação. Mas por que não executar todos os testes no servidor de desenvolvimento? Um dos motivos é que todos os testes da aplicação podem demorar muito para serem executados. Além disso, também é necessário criar builds completos da aplicação para que a cada commit seja disponibilizada uma versão funcional e pronta para execução. A versão da aplicação após o processo bem sucedido de integração contínua está pronta para implantação no servidor de produção. Portanto, além dos ambientes já citados, recomenda-se também o uso de um ambiente de integração contínua para melhor acompanhamento e auxílio durante o desenvolvimento. Há algumas diferenças na implantação entre o a versão 2 do Play e a versão que estamos trabalhando neste minicurso, na versão 1.2.x esse processo pode ser considerado ate mais fácil.Uma aplicação desenvolvida no Play Framework pode ser executada a partir do terminal através do comando play run. É possível a geração de um arquivo WAR(Web Application Archive) com o objetivo da implantação em servidores JEE, como por exemplo o Tomcat. Heroku é uma plataforma nas nuvens que atua como um serviço (PaaS) em que é possível fazer o deploy de várias aplicações em várias linguagens, inclusive Java. Especificamente o Heroku já possui alguns serviços em que é possível fazer deploy de aplicações de SaaS baseadas no Play Framework. Serviços de PaaS, como o Heroku, simplificam o trabalho do desenvolvedor, conforme explicado na seção 1.4 (Computação em Nuvem). Também é possível armazenar a aplicação em um repositório GIT, o qual será explicado adiante, e a partir dele, enviar a aplicação para o Heroku ou outro serviço de PaaS. Neste capítulo abordamos o uso do Heroku, pela facilidade de uso e por permitir a implantação e a execução gratuitas de aplicações que atendam a determinados limites definidos pelo serviço. A ausência de custo torna-se atrativa no contexto acadêmico de uso do serviço para fins de aprendizagem. No entanto, outros bons serviços poderiam ter sido usados. Para realizar a implantação é necessário criar uma conta no Heroku e configurar o GIT na máquina local, pois o Heroku atualiza os arquivos da aplicação a partir de um repositório GIT. A seguir são descritos os passos necessários para publicação da aplicação nas nuvens através do Heroku. 1. Crie a aplicação no Heroku heroku create 2. Faça a implantação do código da aplicação git push heroku master Os passos acima são suficientes para disponibilizar a aplicação nas nuvens. Pode-se acessá-la através de um link gerado pelo Heroku e que aparecerá no terminal após a publicação da aplicação. É possível ver registros (logs) da aplicação através do comando heroku logs. O gerencimanento da aplicação, quantidade de espaço utilizado, endereço da aplicação, entre outras coisas, pode ser realizado através da interface administrativa do Heroku. Esta seção destacou a importância do uso de ambientes fisicamente separados para a execução da aplicação durante as diversas etapas do desenvolvimento do software, desde a sua modelagem até a visualização e utilização do software pelo cliente. Servidores de integração contínua são úteis para teste da aplicação, após o recebimento de variadas contribuições dos membros da equipe, fornecendo uma visão clara e geral de possíveis erros. 1.9. Uso de sistemas de controle de versão e modelos de fluxo de trabalho A ideia de usar sistemas de controle de versão é muito importante, especialmente, quando o desenvolvimento ocorre em equipe. Eles possibilitam um controle e gerenciamento mais efetivo sobre os detalhes das diversas modificações ocorridas no software ao longo do tempo, além de facilitar bastante o trabalho colaborativo durante o desenvolvimento do software. É possível, por exemplo, recuperar uma versão anterior de uma determinada classe ou mesmo resolver conflitos decorrentes de dois desenvolvedores alterarem simultaneamente um mesmo trecho de código. GIT é um sistema que permite o controle de versão e o gerenciamento de código fonte de forma rápida e eficiente. Ele foi inicialmente desenvolvido por Linus Torvalds, também criador do Linux, para servir como sistema de versionamento do núcleo do Linux. Por sua rapidez e facilidade, ele tem sido bastante utilizado na comunidade que trabalha com desenvolvimento Ágil. O uso do GIT permite a aplicação de algumas técnicas de fluxo de trabalho relacionadas à forma de utilização de repositórios locais e remotos. A criação de um repositório com o GIT, ocasiona a criação, por padrão, de um repositório local denominado master. A adição de um repositório remoto, por padrão gera um repositório denominado origin. Com esses dois repositórios, é possível fazer com que o fluxo de trabalho seja uma transferência das alterações locais para as remotas, de forma que ao fazer alterações localmente, pode-se enviar essas alterações ao repositório remoto. Essa é a forma mais comumente usada para lidar com GIT. Contudo, apresentaremos uma forma semelhante a essa, porém capaz de simplificar ainda mais o controle de versões. O fluxo de trabalho que apresentaremos foi inicialmente utilizado pela HashRocket17, uma empresa americana de desenvolvimento ágil. O fluxo foi chamado Hack-Sink-Ship por seus próprios criadores e seu objetivo principal é poupar tempo ao fazer com que o processo de enviar e sincronizar alterações seja mais rápido. Scripts simples podem implementar o fluxo, usando apenas alguns comandos GIT. Não há uma tradução para o termo em português, entretanto, podemos tecer alguns comentários sobre cada um deles. Hack pode ser traduzido do inglês como picar ou como sinônimo de cortar, dando uma ideia de recorte de uma certa funcionalidade, de forma que o desenvolvedor possa trabalhar apenas nela. Com relação ao sink, temos a noção de sincronização. Assim, caso alguma nova modificação no repositório remoto ocorra, deve-se sincronizar com as novas alterações realizadas localmente. Por último, o termo ship em uma tradução praticamente literal do inglês, significa “deixar pronto para uso”. Desse modo, executar um ship significa deixar a feature pronta para uso. Hack-sink-ship baseia-se no fato de que com o GIT devemos sempre leva em conta a sincronização entre dois repositórios. Inicialmente tínhamos um repositório local e outro remoto e, então, havia uma sincronização entre os mesmos. Em seguida, passamos a ter um repositório para cada funcionalidade implementada. Assim, temos: o repositório master, o origin, além de um repositório para cada funcionalidade. Geralmente em equipes ágeis, a funcionalidade a ser implementada possui um número 17 http://hashrocket.com/ identificador. Então, pode-se usar esse número para representar o branch onde ficará a implementação da nova funcionalidade. No exemplo a seguir, a variável ATUAL contém o valor numérico do identificador da funcionalidade. Basicamente as operações funcionam como scripts contendo uma pequena sequência de comandos GIT: ● Hack: cria o branch que terá apenas as alterações referentes a uma determinada funcionalidade. git checkout master git pull origin master git checkout -b $ATUAL master ● Sink: Sincroniza o repositório atual da funcionalidade com o repositório origin. Com isso, antes do envio das alterações, checa-se se o código será bem aceito, isto é, se ele não gerará erros ao ser integrado com as demais funcionalidades existentes. Isso pode ocorrer quando algum desenvolvedor efetua alterações antes de outro, em um mesmo trecho de código. git checkout master git pull origin master git checkout $ATUAL git rebase master $ATUAL ● Ship: Faz um merge do branch atual da funcionalidade com o master, e envia as alterações para o repositório origin.git checkout master git merge --squash $ATUAL git commit -a -v git push origin master Agora serão descritos os momentos ideais para cada uma dessas operações. Inicialmente, quando uma funcionalidade é atribuída ao desenvolvedor, deve-se evitar que as alterações necessárias para implementá-la não causem problemas ao código anterior. Assim, executa-se o hack, fazendo um branch somente para a funcionalidade. Para testar, sincroniza-se executando o sink. Se todos os testes passarem, a funcionalidade foi integrada com sucesso ao código anterior da aplicação e, então, ela pode ser integrada juntamente com o restante da aplicação, que se encontra remota. Depois disso, faz-se um ship para que o código seja enviado. O fluxo Hack-Sink-Ship é muito simples de ser implementado e pode simplificar bastante o desenvolvimento em equipe. Aliando esse fluxo de trabalho a serviços de integração contínua, pode-se monitorar e obter total controle sobre o código. Ressalta-se ainda que a adoção desse fluxo permite que o desenvolvedor se dedique mais a outras tarefas, como testes, por exemplo. Além disso, após a execução bem sucedida do fluxo, pode-se realizar os testes para ter a certeza de que a aplicação funciona com a novas contribuições dos demais membros da equipe de desenvolvimento. A seguir, sugerimos um fluxo de trabalho mais completo, que se integra às práticas supracitadas de uso do hack-sink-ship: 1. Inicie a funcionalidade a ser implementada. 2. Faça um hack, criando um branch para sua funcionalidade. 3. Escreva os testes. 4. Valide a implementação com os testes escritos. 5. Repita os passos 3 e 4 até que a funcionalidade esteja completa. 6. Faça um sink, sincronizando com alguma eventual alteração feita no origin, posterior a sua versão do sistema. 7. Envie suas alterações através da execução do ship. Portanto, vimos que a utilização desse fluxo de trabalho para o desenvolvimento ágil de uma forma geral pode ser bem empregado, facilitando a forma de enviar alterações, assim como a sincronização das mesmas. Essa é apenas uma proposta que achamos conveniente utilizar, podendo ocorrer variações da mesma. 1.10. Conclusão A forma como o mercado de software desenvolveu-se e a presença de sistemas computacionais em quase todos os dispositivos de nosso cotidiano, desde alguns dos mais simples aparelhos celulares até o mais complexo controlador de tráfego aéreo, fez com que a indústria de desenvolvimento de software focasse cada vez mais na qualidade e eficiência de seus produtos. Uma das maneiras de se garantir a qualidade de um produto de software é a utilização da Engenharia de Software. Contudo, além da qualidade, os clientes buscam rapidez na entrega dos produtos e a evolução da internet como um meio de serviço leva os desenvolvedores ao uso de Metodologias Ágeis para a construção de software robusto e com garantias de boa qualidade. Diante da necessidade de um desenvolvimento de software mais dinâmico e eficiente, este capítulo apresentou uma proposta de uso da arquitetura MVC e do modelo de Software como Serviço (SaaS), uma vez que ambos viabilizam agilidade no desenvolvimento e melhor interação do usuário com o sistema. O grande crescimento da Internet e os custos cada vez mais baixos de serviços de computação em nuvem viabilizam um enorme crescimento do número de aplicações que seguem o modelo de SaaS. Apenas o uso de metodologias não garante a qualidade do produto final. Manter a cultura dos testes de software é tão importante quanto o correto uso da Engenharia de Software durante a construção da aplicação para garantir que o dinamismo das exigências dos usuários sejam satisfatoriamente atendidas. O capítulo abordou algumas das principais técnicas da Engenharia de Software vinculadas ao desenvolvimento ágil como um incentivo aos novos desenvolvedores a perpetuarem as melhores práticas de desenvolvimento de software, garantindo sempre eficiência na entrega e qualidade no produto final. Referências Armbrust, M., Fox, A., Griffith, R., Joseph, A. D., Katz, R., Konwinski, A., Lee, G., Patterson, D., Rabkin, A., Stoica, I., and Zaharia, M. (2010). “A view of cloud computing”. Commun. ACM, 53(4):50–58. Beck, K., et al. (2001). "Manifesto for Agile Software Development". Agile Alliance. http://agilemanifesto.org/. Acessado em 18 de agosto de 2012. Brantner, M., Florescu, D., Graf, D., Kossmann, D., and Kraska, T. (2008). “Building a database on s3”. In Proceedings of the 2008 ACM SIGMOD international conference on Management of data - SIGMOD ’08, page 251, New York. ACM Press. Chelimsky, D., Astels, D., Helmkamp, B., North, D., Dennis, Z., and Hellesoy, A. (2010). “The RSpec Book: Behaviour Driven Development with Rspec, Cucumber, and Friends”. Pragmatic Bookshelf Series. Pragmatic Bookshelf. David C., Dave A., Zach D., Aslak H., Bryan H., Dan N. (2010) “The RSpec Book: Behaviour Driven Development with RSpec, Cucumber, and Friends”, Pragmatic Bookshelf, 2010. Fielding, R. (2000). “Architectural Styles and the Design of Network-based Software Architectures”. PhD thesis, University of California, Irvine. Fox, A., Patterson, D. (2012). “Engineering Long-Lasting Software: An Agile Approach Using SaaS and Cloud Computing”, Alpha Edition. Strawberry Canyon LLC, 2012. Hoelzle, U. and Barroso, L. A. (2009). “The Datacenter as a Computer: An Introduction to the Design of Warehouse-Scale Machines”. Morgan and Claypool Publishers, 1st edition. ISTQB. (2011). Certified Tester Foundation Level Syllabus, version 2011. Liu, C. (1996). “Smalltalk, objects, and design”. Prentice-Hall, Inc., Upper Saddle River, NJ, USA. Liu, S., Liang, Y., and Brooks, M. (2007). Eucalyptus: a web service-enabled e- infrastructure. In CASCON ’07: Proceedings of the 2007 conference of the center for advanced studies on Collaborative research, pages 1–11, New York, NY, USA. ACM. Paula Filho, W. P. (2006). “Engenharia de Software: fundamentos, métodos e padrões”, 3 ed. Rio de Janeiro: LTC, 2006. Pautasso, C., Zimmermann, O., and Leymann, F. (2008). “Restful web services vs. "big"’ web services: making the right architectural decision”. In Proceedings of the 17th international conference on World Wide Web, WWW ’08, pages 805–814, New York, NY, USA. ACM. Pressman, R. S. (2005). “Software engineering: a practitioner’s approach”, 6 ed. New York: MacGraw-Hill, 2005. Serman, D. V. (2010). “Orientação a projetos: uma proposta de desenvolvimento de uma arquitetura orientada a serviços”. JISTEM: Journal of Information Systems and Technology Management, Sin mes, 619-638. Sousa, F. R. C., Moreira, L. O. e Machado, J. C. (2009). “Computação em Nuvem: Conceitos, Tecnologias, Aplicações e Desafios”. In: Santos Neto, P. (Org.). III Escola Regional de Computação Ceará - Maranhão - Piauí, ERCEMAPI 2009, 1 ed. SBC, Piauí. Sousa, F. R. C., Moreira, L. O., Macedo, J. A. F. e Machado, J. C. (2010). “Gerenciamento de Dados em Nuvem: Conceitos, Sistemas e Desafios”. In: XXV Simpósio Brasileiro de Banco de Dados, 2010, Belo Horizonte. SBBD 2010.
Compartilhar