Categoria: Desenvolvimento (Página 3 de 8)

Noções e Técnicas de Estimação de Software

Este artigo é o Capítulo IV da minha monografia de Especialização em Engenharia de Software. Embora seja um referencial teórico e não acrescente nada de novo, espero que o possa ser útil de alguma forma para o leitor.

Introdução

A estimação de software é fundamental para qualquer projeto. Estimativas de custo, esforço e prazo são geralmente demandadas por clientes e o gerente do projeto precisa ter uma base para o planejamento e para tomar decisões no decorrer do projeto. A estimação também contribui para um maior entendimento do problema e provê um horizonte para a conclusão do projeto ou da iteração.

Existem diversas técnicas, abordagens e modelos de estimação. Este capítulo apresenta alguns deles com a finalidade de prover ao leitor uma visão geral sobre o tema.

Definições relacionadas à estimação

Estimar é prover uma visão do projeto clara o suficiente para que a gerência possa tomar boas decisões de como gerenciar o projeto para que o mesmo atinja seus objetivos (McConnell, 2006). Um dos propósitos da estimação é determinar se esses objetivos são tangíveis o suficiente para que o mesmo possa ser gerenciado de forma a atingir esses objetivos (Pressman, 2009, p. 519).

Boas estimativas são as que levam a decisões de negócio corretas (McConnell, 2006). A organização sofre prejuízo ao executar um projeto onde o orçamento e os esforços reais ultrapassam os valores estimados em uma determinada escala. Portanto, boas estimativas seriam aqueles que fornecessem a aproximação necessária para que o orçamento e o esforço fossem estabelecidos com uma margem adequada.

McConnell (2006) define boas estimativas do ponto de vista estatístico como aquelas que variam em 25% ou menos, durante pelo menos 75% das vezes. O critério arbitrário do autor reforça o conceito de que boas estimativas são as que proporcionam boas aproximações suficientes para que a maioria das decisões sobre projetos estejam corretas.

Uma estimativa não é uma medida, mas uma suposição sobre algo que se espera ser verdadeiro. Técnicas e modelos matemáticos podem dar a falsa impressão de acurácia, mas previsões sobre o software são sempre baseadas em julgamentos subjetivos com base em uma definição abstrata do sistema.

Estimativas não devem ser ajustadas para se adequar ao objetivo de negócio da empresa ou do cliente, tal como para atender um prazo arbitrário. O esforço de desenvolvimento e a complexidade do software não mudam devido a esses aspectos. Quando é necessário entregar um software antecipadamente, devem-se ajustar outras variáveis para que o esforço necessário seja atingido em um tempo menor.

Uma estimativa não é um compromisso (McConnell, 2006). Os executivos de uma organização geralmente querem um compromisso e um plano para alcançar um objetivo de negócio. Embora o compromisso e o plano possam ser baseados em estimativas, é importante diferenciar os conceitos.

Além disso, a estimação deve considerar diversas influências sobre o desenvolvimento de software. Ao se estimar devem ser considerados fatores relacionados ao problema, ao cliente, ao ambiente de desenvolvimento e às pessoas envolvidas, os quais influenciam diretamente no projeto de software.

Segundo McConnel, a atividade de estimação seria análoga a uma arte ao invés de um processo científico (McConnell, 2006). Embora técnicas e modelos forneçam uma abordagem consistente para a estimação, o conhecimento, a experiência e as habilidades do estimador são determinantes para a qualidade das estimativas.

Grau de incerteza das estimativas

As estimativas possuem grau de incerteza variável no decorrer do projeto (McConnell, 2006). Elas são incertas por natureza (Pressman, 2009, p. 520), mas a incerteza pode diminuir ao passo em que medidas do projeto são coletadas e o problema conhecido mais detalhadamente. Este pensamento é exemplificado na Figura 6, onde Cohn (2006, p. 4) apresenta o Cone da Incerteza.

Figura 6 - Cone da Incerteza (Cohn, 2006, p. 4)

Figura 6 – Cone da Incerteza (Cohn, 2006, p. 4)

As estimativas podem ser analisadas do pondo de vista probabilístico. Ao invés de um valor absoluto, considera-se uma faixa de valores com maior probabilidade de conter o valor real. No início do projeto a incerteza atinge seu ápice, mas diminui na medida em que as tarefas são concluídas, os riscos mitigados e o gerente pode avaliar o que realmente foi realizado em contraste com o que foi previamente planejado. A incerteza é mínima ao final do projeto, quando todas as atividades estão concluídas e o esforço necessário para completá-las contém o valor que reflete a realidade.

Entretanto, o grau de incerteza representado pelo Cone da Incerteza (Figura 6) reflete a menor incerteza possível num determinado ponto do projeto. McConnell (2006) afirma que o comum é a incerteza ser maior do que a apresentada no gráfico, principalmente em projetos onde não se tomam as precauções necessárias em cada fase através de um gerenciamento adequado.

Barreiras e influências na estimação de software

Não existe uma forma de estimação determinística. Esforços e recursos foram despendidos para criar e aperfeiçoar técnicas e modelos de estimação, mas características como mutabilidade dos requisitos e a intangibilidade do software os tornam inerentemente difícil de estimar.

Barreiras na elicitação de requisitos fazem parte dos principais fatores que tornam a estimação difícil. Como apresentado no capítulo II, os requisitos mudam ao longo do tempo. Muitos tipos de domínios sofrem mudanças muito rapidamente, outros são muito complexos, há casos onde os usuários não conseguem definir suas necessidades ou o conhecimento está fragmentado de tal forma que não é possível identificar com precisão o que deve ser desenvolvido.

As características do software também dificultam a tarefa de estimação. Identificar a solução completa para um problema é um desafio. O software é um produto abstrato, desenvolvido em um processo diferente da engenharia convencional, pois cada software é único. Tudo isso torna desafiadora a tarefa de prever o esforço de desenvolvimento.

Além disso, os projetos de software são imprevisíveis e ocorrências podem invalidar a estimação realizada. Brooks (1975) afirma que “nossas técnicas de estimativa são mal desenvolvidas […] elas não refletem um pressuposto não mencionado, que não é muito verdadeiro, isto é, de que tudo irá correr bem.” Brooks acrescenta que a pressão externa pode resultar em estimativas tendenciosas e ruins, pois “frequentemente falta aos gerentes de software firmeza de fazer o pessoal esperar por um bom produto”.

Imprevistos podem ocorrer de diversas formas no decorrer do projeto. Alguns tipos de imprevistos incluem aspectos já discutidos neste estudo sobre o software e os requisitos. Pressman (2009, p. 520) identifica e classifica uma série de fatores que impactam no custo e no esforço de desenvolvimento, conforme a tabela a seguir.

Tabela 3 – Fatores que impactam no desenvolvimento de software (Pressman, 2009, p. 520)

Fatores Exemplos
Humanos Pedidos de demissão, problemas pessoais, habilidades dos indivíduos.
Ambientais Dificuldade de comunicação com cliente ou entre a equipe de desenvolvimento, mudanças no negócio, no escopo ou no domínio.
Políticos Mudanças em leis, nas políticas da empresa.
Técnicos Ferramentas de desenvolvimento apresentam problemas ou possuem limitações difíceis de contornar, mudanças e restrições tecnológicas.

Existem problemas que, quando presentes em um projeto, influenciam negativamente na estimação, a qual dificilmente refletirá a realidade. McConnell (2006) identifica alguns desses problemas, os quais estão descritos na tabela abaixo.

Tabela 4 – Influências negativas sobre a estimação (McConnell, 2006)

Processo de desenvolvimentocaótico Ocorre quando há falha em uma ou mais partes do projeto. Por exemplo: requisitos não elicitados adequadamente desde o início, falta de envolvimento dos usuários na validação dos requisitos, práticas de codificação ruins, inexperiência da equipe, plano de projeto incompleto, abandono do plano nos momentos de pressão, falta de gerenciamento automatizado do código.
Requisitos instáveis Mudanças são esperadas, mas os requisitos precisam estar bem definidos em algum momento, caso contrário a estimação não será adequada nem mesmo em fases avançadas do projeto.
Atividades omitidas Umas das fontes mais comuns de problemas é o esquecimento de incluir atividades essenciais. Alguns exemplos comuns são: instalação do sistema, conversão de dados, adequação e uso de bibliotecas de terceiros, ajuda ao usuário, interfaces com sistemas externos. Além disso, alguns requisitos não funcionais também são esquecidos, tais como desempenho, confiabilidade, escalabilidade, segurança, entre outros.
Otimismo sem fundamento Desenvolvedores tendem a gerar estimativas otimistas com fator de vinte a trinta por cento, em média.
Subjetividade e tendência pessoal Tendências pessoais conscientes ou inconscientes do estimador geram erros de estimação para mais ou para menos.
Estimativas informais Estimativas repassadas de desenvolvedores para seus superiores, sem que haja tempo hábil para avaliar criteriosamente a situação, provavelmente serão bem diferentes da realidade.
Precisão não necessária O termo precisão não deve ser confundido com acurácia. Acurácia significa estar próximo da realidade, enquanto precisão está mais relacionada ao nível de detalhamento, por exemplo, o número de casas decimais de um resultado. Estimativas demasiadamente precisas e detalhadas não necessariamente são verdadeiras. Uma estimativa com precisão de horas não tem utilidade. Uma boa prática seria estimar com base em semanas, meses ou o que for adequado para o tamanho do projeto, resultando numa maior acurácia.

Além disso, as estimativas também são influenciadas por características do projeto e da equipe. A influência pode ser positiva ou negativa, dependendo de cada característica. McConnell (2006) cita quatro características do projeto e da equipe descritas na tabela a seguir.

Tabela 5 – Características do projeto que influenciam estimativas (McConnell, 2006)

Tamanho do projeto O esforço por linha de código aumenta proporcionalmente ao tamanho do projeto. É importante descobrir o porte do projeto para depois ajustar as estimativas individuais.
Tipo de software O rendimento da equipe varia dependendo da área para a qual o software está sendo desenvolvido. Por exemplo, softwares desenvolvidos para uma intranet chegam a ter um rendimento vinte vezes maior do que softwares construídos para a aeronáutica.
Fatores pessoais Estudos mostram que o desempenho pode variar numa escala de dez vezes entre indivíduos. As estimativas devem ser ajustadas conforme o desempenho dos desenvolvedores envolvidos.
Linguagem de programação ou tecnologias Ao usar o número de linhas de código como base para as estimativas, deve-se usar um fator de ajuste dependendo da linguagem utilizada. O mesmo pode ser estendido para outras tecnologias envolvidas.

Pressman (2009, p. 525) também destaca algumas influências que devem ser consideradas na estimação. Segundo o autor, mesmo que o software a ser estimado fosse relativamente estático em relação ao ambiente e aos requisitos, existem fatores externos que influenciam diretamente na qualidade das estimativas, tais como:

  • o grau de precisão com que o planejador estimou o tamanho do produto a ser construído;
  • a precisão para transformar a estimativa de tamanho em esforço humano, tempo e custo;
  • experiência do gerente;
  • acesso a boas informações históricas.

Enfim, a estimação é uma atividade desafiadora que possui diversas influências e dificuldades intrínsecas oriundas das barreiras do desenvolvimento de software e da natureza dos requisitos, das várias influências e das características do projeto, além do risco de problemas que podem ocorrer durante o projeto.

Princípios gerais de estimação

Existem princípios que podem ser aplicados a qualquer forma de estimação. Embora as diferentes técnicas e modelos de estimação sejam diferentes em diversos aspectos e aplicáveis em diferentes contextos, a natureza das estimativas permanece a mesma.

Quanto mais cedo ocorrer a estimação, piores serão as estimativas (Pressman, 2009, p. 524). A estimação antecipada de todo o software tende a gerar estimativas piores do que em casos onde elas são feitas em fases posteriores do projeto (Pressman, 2009, p. 520). Embora muitas vezes seja necessário estimar todo o software, é importante refazer a estimação quando se deseja obter uma posição atualizada sobre o estágio de desenvolvimento.

Além disso, informações de projetos semelhantes já completados tendem a deixar as estimativas melhores. Dessa forma, é possível prever com mais exatidão o esforço necessário ao se basear em experiências anteriores.

A decomposição do projeto e do software em unidades menores também ajuda na estimação. Isso facilita ao estimador manter o foco e ter uma visão mais clara do que ele está estimando. Além disso, é mais fácil encontrar informações históricas de componentes de software semelhantes já desenvolvidos.

Estimativas de componentes do software podem ser feitas utilizando medidas relativas (Cohn, 2006, p. 34). Em técnicas que utilizam este recurso, atribui-se um valor relativo a cada componente ou funcionalidade do sistema. Então a estimativa final é calculada baseando-se em dados de projetos semelhantes ou com base no que já foi desenvolvido do projeto corrente. Dessa forma, não é necessário refazer as estimativas individuais dos componentes do sistema no decorrer do projeto, sendo necessário apenas ajustar o fator usado para calcular a estimativa final de acordo com as avaliações do projeto.

A qualidade de uma estimativa pode ser verificada utilizando um segundo método de estimação. Quando o estimador está incerto sobre uma estimativa e deseja uma certeza maior sobre a mesma, pode-se realizar uma nova estimação através de outra técnica ou modelo a fim de averiguar se a primeira estimativa era confiável.

Entretanto, não é recomendado investir esforço demasiado na estimação. Esforços exagerados em melhorar as estimativas podem resultar num efeito contrário ao esperado, gerando distorção nos valores obtidos. Cohn (2006, p. 54) fez um levantamento sobre os esforços para obter melhores estimativas e percebeu que, a partir de um determinado momento, quanto mais tempo é investido nessa tarefa, mais o resultado estará longe da realidade (Figura 7).

Figura 7 - Gráfico de Escorço x Acurácia das Estimativas (Cohn, 2006, p. 54)

Figura 7 – Gráfico de Escorço x Acurácia das Estimativas (Cohn, 2006, p. 54)

Estimação indireta

Algumas das técnicas de estimação são indiretas (McConnell, 2006). Por exemplo, dividir o sistema em componentes e estimar baseando-se nas características dos componentes ou estimar através de uma classificação das funcionalidades utilizando lógica fuzzy (categorizando cada funcionalidade como muito pequena, pequena, média, grande ou muito grande) são formas indiretas de estimação. Após a estimação dos elementos do software calcula-se a estimativa final de acordo com a técnica utilizada.

Aplicabilidade das técnicas e modelos de estimação em processos

A escolha de uma técnica ou modelo de estimação em um projeto pode ser definida com base no processo de desenvolvimento adotado. Características do processo podem inviabilizar ou recomendar o uso de determinada técnica ou modelo de estimação. Processos ágeis que utilizam histórias de usuário para ilustrar as funcionalidades do sistema dificultam a aplicação de técnicas de estimação que dependem de um modelo de análise e design.

Técnicas de estimação que exigem detalhamento do sistema são mais recomendados para processos disciplinados ou que exigem maior burocracia. Em geral, essas técnicas de estimação partem do modelo de análise procurando antecipar o tamanho e a complexidade do software (Pressman, 2009, p. 357). O modelo de análise deve estar detalhado o suficiente para permitir que seus elementos sejam estimados. Como os processos burocráticos dão grande importância ao planejamento antecipado como um dos fatores mais críticos para o sucesso ou a falha de um projeto (Pressman, 2009, P. 519) então uma técnica de estimação mais detalhada torna-se adequada.

Por outro lado, técnicas empíricas baseadas em julgamento humano de funcionalidades ou características de alto nível de um software são recomendadas quando a organização adota processos com pouca burocracia, tal como processos ágeis.

Estimação em processos ágeis

A estimação nos processos ágeis é, em geral, baseada em histórias de usuário (Cohn, 2006, p. 34). A unidade de medida comumente utilizada é a story point (ponto de história), que indica o tamanho de uma história de usuário que está no backlog do produto, numa escala definida para o projeto em questão. Os story point atribuídos às histórias de usuários possuem valor relativo entre as várias histórias, com o objetivo de permitir a comparação.

Uma história de usuário é detalhada em tarefas individuais para a equipe de desenvolvimento no início da iteração em que foi selecionada para ser implementada. O esforço das tarefas é então estimado em horas. É recomendado que uma tarefa não tenha duração de mais de um dia de trabalho.

A estimação em processos ágeis é feita pela equipe. Os agilistas enfatizam que a estimação é mais bem feita pelos indivíduos que efetivamente criam o software, ao invés de um analista ou gerente.

Além disso, a estimação deve ser em equipe, de modo que todos ou a maioria concorde com cada estimação. Deve-se evitar que um membro influencie o outro na estimação inicial, pois um membro da equipe poderia ter receio de ter uma opinião muito diferente sobre determinadas estimativas. Cada membro da equipe teria o potencial de apresentar uma perspectiva sobre um determinado requisito que os demais não conseguiram visualizar. Dessa forma, haveria uma verificação coletiva de cada estimativa.

Modelo básico da atividade de estimação

A atividade estimação pode ser dividida em três tarefas básicas, independente do modelo ou técnica utilizada (McConnell, 2006).

Primeiramente, deve-se realizar a escolha da técnica de estimativa considerando o tamanho e o estágio atual do projeto, o processo de desenvolvimento (iterativo, sequencial, evolutivo) e a acurácia possível.

Em seguida, o estimador deve contar, computar e julgar de forma adequada os elementos que servirão como base das estimativas, tais como linhas de código, horas de trabalho ou pontos de história;

Finalmente, deve-se calibrar a contagem realizada. Isso é feito utilizando dados históricos de projetos passados ou de iterações anteriores do mesmo projeto e avaliando características internas e externas que influenciam o projeto. Desse modo, a contagem pode ser realmente considerada uma estimativa.

Técnicas e modelos de estimação

Estimação orientada a objetos

Sistemas orientados a objetos podem ser estimados através de modelagem orientada a objetos, como a UML (Unified Modeling Language). Atribui-se valores a cada objeto do sistema e, assim, pode-se chegar a uma estimativa geral.

Algumas medidas sugeridas por Pressman (2009, p. 506) são:

  • número de scripts de cenários de interação entre usuário e o sistema;
  • número de classes importantes e independentes do sistema;
  • número de classes de apoio não relacionadas ao domínio (banco de dados, interface com usuário);
  • número de classes de apoio relacionadas ao domínio;
  • número de subsistemas.

Estimação orientada a casos de uso

É possível utilizar casos de uso para estimar um software. As estimativas de cada caso de uso possibilitariam planejar o projeto com um todo.

Entretanto, como casos de uso são muito abstratos e pessoas diferentes trabalham em diversos níveis de abstração. Não há parâmetros para definir uma medida padrão para o esforço necessário para implementar um dado caso de uso (Pressman, 2009, p. 507). Em decorrência disso, a estimação com casos de uso não é recomendada, sendo pouco utilizada.

Estimação orientada a componentes

Um sistema pode ser dividido em componentes de acordo com as características de seus componentes. Por exemplo, um sistema com arquitetura para a web poderia ter seus elementos classificados em páginas dinâmicas, páginas estáticas, tabelas de banco de dados, relatórios e regras de negócio (McConnell, 2006). Cada conjunto representa um componente, cujos elementos são semelhantes.

Dados históricos classificados de acordo com os tipos de componentes ou o julgamento de um especialista podem ser usados para estimar o número de linhas de código ou esforço necessário para desenvolver cada componente.

Estimação baseada no julgamento de um especialista

Esta técnica consiste em dividir o desenvolvimento do aplicativo de software em tarefas utilizando uma granularidade adequada, isto é, dividindo tarefas grandes, de longa duração ou complexas, em menores e utilizando faixas de estimativas com melhor e pior caso. Esses valores são usados para derivar uma estimativa final que possuiria grande probabilidade de sucesso.

Na medida em que o projeto evolui, o estimador compara os dados obtidos das tarefas já concluídas com as estimativas originais e calcula o erro relativo, ajustando os valores estimados para as tarefas futuras.

Através dessa técnica, um estimador que realiza seu trabalho de forma estruturada e não apenas intuitiva pode conseguir bons resultados (McConnell, 2006). Apesar de ser totalmente empírico, este é o método mais utilizado nas organizações.

Estimação por analogia

Consiste em estimar um projeto baseando-se em outro com arquitetura semelhante já concluído, ou seja, que possui dados reais sobre as tarefas realizadas.

Esta técnica pode gerar grandes erros se usado de forma indevida (McConnell, 2006). Primeiramente é necessário possuir dados precisos e detalhados sobre o projeto antecessor. Uma boa prática seria construir as novas estimativas como uma porcentagem em relação ao projeto anterior, comparando o tamanho de ambos. Ainda assim é necessário considerar diferenças importantes, tais como tecnologias diferentes, tamanhos muito distintos, equipe diferente, etc.

Estimação por Ponto de Função (Function Point)

A técnica de estimativa por ponto de função se propõe a medir o tamanho das funcionalidades de um sistema (Pressman, 2009, p. 357). Através de uma lista dos elementos do software a serem construídos, avaliações da complexidade desses elementos e dados históricos, seria possível estimar:

  • custo e esforço do desenvolvimento;
  • quantidade de erros encontrados nos testes;
  • número de componentes e linhas de código projetadas no sistema.

As entradas necessárias para realizar a estimação são:

  • número de entradas externas: entrada de dados pelo usuário ou por outra aplicação;
  • número de saídas externas: saída que fornece informação ao usuário (relatórios, telas, etc.);
  • número de consultas externas: chamada on-line com resposta imediata, como uma chamada de serviço por outra aplicação;
  • número de arquivos lógicos internos: quantidade de agrupamentos de dados, tal como tabelas, arquivos de dados, entre outros;
  • número de arquivos de interface externa: dados externos acessados pela aplicação.

Cada entrada é extraída de modelo da aplicação. A partir dos dados obtidos, cada elemento é contado, avaliado e categorizado em níveis de complexidade, geralmente de forma subjetiva, como simples, médio ou complexo. O resultado é utilizado para calcular uma contagem total dos pontos, conforme a figura abaixo:

Figura 8 - Exemplo de Estimativa por Ponto de Função (Pressman, 2009, p. 359)

Figura 8 – Exemplo de Estimativa por Ponto de Função (Pressman, 2009, p. 359)

Alguns valores de ajuste (Fi) são definidos baseados em respostas com valores de “0” (não importante) até “5” (absolutamente essencial) às catorze descritas na tabela a seguir:

Tabela 6 – Fatores de ajuste da técnica de estimação por pontos de função (Pressman, 2009, p. 357)

1 O sistema precisa de backup?
2 Modos de transferência de dados específicos são usados para importar ou exportar dados?
3 Existe processamento distribuído?
4 O desempenho é crítico?
5 O sistema funcionará em um ambiente operacional existente, intensamente utilizado?
6 O sistema requer entrada de dados online?
7 A entrada online exige que a transação seja construída por várias telas ou operações?
8 Os arquivos lógicos internos são atualizados online?
9 As entradas, saídas, arquivos ou consultas são complexos?
10 O processamento interno é complexo?
11 O código foi projetado para ser reusado?
12 A conversão e instalação estão incluídas no projeto?
13 O sistema está projetado para instalações múltiplas em diferentes organizações?
14 A aplicação está projetada para facilitar modificações no uso do usuário?

Ao final, aplica-se a seguinte equação para obter o valor de pontos de função:

Figura 9 - Equação para obter o resultado da métrica por pontos de função

Figura 9 – Equação para obter o resultado da métrica por pontos de função

Os níveis de complexidade e os fatores de ajuste são valores subjetivos, pois dependem completamente da experiência e intuição do estimador. Entretanto, eles mesmos podem ser ajustados através de um histórico de dados colhidos em projetos anteriores (Pressman, 2009, p. 505).

A quantidade de linhas de código de um sistema (LOC – Line of Code) pode ser derivada a partir dos pontos de função. Através de estimativas grosseiras da quantidade de linhas de código da linguagem de programação escolhida por ponto de função, a quantidade total de linhas de código é calculada, através de simples multiplicação, e utilizada para prever o tamanho do sistema.

Modelo COCOMO II

COCOMO (Constructive Cost Model) é um modelo para estimar custo, esforço e cronograma durante o planejamento de projetos de software. Ele foi inicialmente publicado por Barry Boehm em 1981 e posteriormente foi lançada uma versão atualizada denominada COCOMO II, em 1995, refletindo a dramática evolução das práticas de desenvolvimento de software (CSSE).

O modelo COCOMO II possui um programa de afiliados que investem técnica e financeiramente no seu desenvolvimento, incluindo grandes empresas e laboratórios de pesquisa. Ele é um modelo aberto, isto é, pode ser usado por qualquer organização, e faz uso intensivo de dados históricos.

O modelo utiliza a seguinte fórmula para calcular o esforço:

Figura 10 - Fórmula de cálculo do esforço do projeto (Boehm, 2005)

Figura 10 – Fórmula de cálculo do esforço do projeto (Boehm, 2005)

Segundo Boehm (2005), a constante A captura o efeito linear do tamanho do projeto no esforço necessário. B é um fator exponencial de ajuste de acordo com o tamanho do projeto. O Tamanho se refere à dimensão do projeto e seu valor pode ser medido em milhares de linhas de código, pontos de objeto ou pontos de função, geralmente derivado de outra técnica de estimativa.

O fator exponencial B é ajustado para cada projeto a partir de um conjunto de fatores definidos no modelo COCOMO II, os quais levam em consideração, por exemplo:

  • se o projeto foi precedido por outro semelhante;
  • se os riscos e a arquitetura são claramente definidos;
  • o entrosamento da equipe;
  • a maturidade do processo.

Além disso, o Esforço Nominal calculado pode ser ajustado por fatores relacionados ao produto, à plataforma, ao projeto e mesmo também pessoais. Por exemplo, o fator DATA permite o ajuste pelo tamanho do banco de dados, RELY considera a confiabilidade exigida do software, CPXL a complexidade do produto, ACAP a capacidade dos analistas, TOOL o uso de ferramentas de desenvolvimento e assim por diante.

Cada fator recebe uma classificação numa escala de cinco níveis (muito baixo, baixo, nominal, alto, muito alto). O ajuste é realizado multiplicando-se os fatores individuais pelo Esforço Nominal.

Clark (1998) define o COCOMO como um modelo paramétrico, ou seja, que utilizada uma representação matemática idealizada do mundo real baseada em parâmetros quantitativos ou qualitativos. Embora os parâmetros sejam derivados, em sua maioria, de julgamentos subjetivos, o modelo propõe que, através dos ajustes adequados, é possível obter uma estimativa com 70% de confiabilidade (Boehm, 2005).

PROBE

O PROBE (Proxy Based Estimating – Estimação Baseada em Proxy) é uma técnica de estimação indireta baseada em objetos e dados históricos (Humphrey, 2000, p.12).

Primeiramente, os engenheiros identificam os objetos necessários para a construção do produto de software e então determinam aproximadamente o tipo e o número de funções de cada objeto. Com base em dados históricos, compara-se cada objeto com objetos similares e estima-se o tamanho do mesmo em linhas de código usando regressão linear.

A estimação do esforço é realizada de forma similar. Com base nos dados históricos, aplica-se a regressão linear para estimar o esforço necessário para o desenvolvimento. Os dados devem mostrar uma relação direta entre o tamanho do programa e o tempo de desenvolvimento.

Para gerar o cronograma, cada engenheiro deve estabelecer em que ele irá trabalhar no projeto semanalmente ou diariamente, calculando-se assim o tempo necessário para conclusão de suas tarefas.

Durante o desenvolvimento, os engenheiros devem armazenar os dados de tempo e tamanho do projeto atual para planejamentos futuros.

Planning Poker

Alguns processos ágeis, como o Scrum, encaram o projeto de software como um jogo. Nessa linha, alguns autores consideram a melhor forma de estimar uma espécie de poker com as histórias de usuário do backlog (Cohn, 2006, p. 55).

No Planning Poker, todos os membros da equipe de desenvolvimento se reúnem. Primeiramente, cada membro recebe cartas. Cada carta contém um valor da escala de story point definida para o projeto. Para cada história de usuário, os membros escolhem secretamente a carta com o valor que consideram ser o tamanho daquela história. Então, todos mostram suas cartas ao mesmo tempo. Quando há consenso, a estimativa seria confiável. Se um ou mais valores forem discrepantes, os membros discutem entre si o motivo porque a história de usuário seria mais ou menos complexa. Após entrarem num consenso, uma nova rodada de cartas é realizada. Isso é feito até que todos estejam de acordo com a estimativa.

Os “agilistas” afirmam que esta técnica tem funcionado bem pelos seguintes motivos (Cohn, 2006, p. 59):

  • aqueles que sabem como fazer o trabalho são os que fazem as estimativas;
  • o diálogo faz com que os estimadores tenham que justificar suas estimativas, portanto eles pensam bem no que estão fazendo;
  • a discussão em grupo, segundo alguns estudos, levam a melhores estimativas.

O Planning Poker geralmente é feito de forma mais intensa, porém menos detalhada, no início do projeto, de modo a gerar as estimativas iniciais necessárias para o planejamento geral e o número de iterações.

No início de cada iteração, sugere-se levar algo em torno de uma hora para detalhar as estimativas das histórias de usuário que serão implementadas, as quais, que nesse ponto, estão dividias em tarefas. O tempo de estimar varia de acordo com o tamanho da iteração.

Estimação por velocidade e aceleração

A velocidade de desenvolvimento é a quantidade de story point que uma equipe consegue implementar em um determinado intervalo de tempo (Cohn, 2006, p. 39). A velocidade pode ser calculada medindo-se o tempo que a equipe levou para concluir cada ponto de história.

A estimação das próximas histórias pode ser feita ou ajustada de acordo com a velocidade da equipe. Além disso, basta aplicar a velocidade às histórias de usuário restantes para obter-se a estimativa geral de conclusão do projeto.

Figura 11 - Gráfico de Velocidade (Cohn, 2006, p. 237)

Figura 11 – Gráfico de Velocidade (Cohn, 2006, p. 237)

A Figura 11 contém um gráfico de velocidade por iteração. A velocidade média permite saber se o projeto está avançando de acordo com o esperado.

A aceleração do desenvolvimento pode ser calculada quando há uma tendência de aumento ou declínio da velocidade de desenvolvimento. Decisões gerenciais podem ser tomadas antecipadamente se os desenvolvedores estão terminando as histórias de usuário mais rapidamente ou mais lentamente a cada iteração.

Conclusão

O uso das técnicas e modelos de estimação depende do contexto. Alguns elementos são complementares, como a técnica de Pontos de Função e o modelo COCOMO, enquanto outros são incompatíveis, tal como o Planning Poker e técnicas semelhantes.

Embora não se possa afirmar definitivamente a superioridade absoluta de um modelo ou técnica, a utilização de um modelo ou técnica adequada pode guiar o estimador a melhores resultados, alavancando suas habilidades através de uma metodologia bem definida.

Por outro lado, qualquer estimador que se apoia em determinado modelo ou técnica como uma “bala de prata” sem compreender a natureza das estimativas, inevitavelmente irá se deparar com uma realidade muito diferente da esperada.

Entender o que são estimativas e no que consiste a tarefa de estimação é fundamental e mais importante do que adotar uma técnica ou modelo em específico.

Noções sobre Processos de Desenvolvimento de Software

Este artigo é o Capítulo III da minha monografia de Especialização em Engenharia de Software. Embora seja um referencial teórico e não acrescente nada de novo, espero que o possa ser útil de alguma forma para o leitor.

Introdução

Um sistema de software é construído através de um processo de desenvolvimento, seja ele formal ou empírico. Diversos modelos de processos surgiram ao longo do tempo, dentro os quais os principais são apresentados neste capítulo.

Ao adotar processos formais e reconhecidos aproveita-se o conhecimento e a experiência dos especialistas que os criaram. Isso inclui boas práticas, listas de verificação, atividades pré-definidas, entre outros. Existe o risco de usar indevidamente o processo, executando todas as atividades propostas sem a devida reflexão, desperdiçando tempo com o que não é importante e gerando uma falsa segurança baseada apenas no fato de se usar um processo conhecido.

Por outro lado, um processo empírico depende da experiência, habilidade e conhecimento da equipe. Profissionais experientes e maduros obtêm vantagens com a liberdade desse tipo de processo porque eles já adotam boas práticas de desenvolvimento, sabem quais atividades são necessárias para completar suas tarefas e sabem como prevenir e resolver problemas.

Existem também processos de gerência utilizados durante o desenvolvimento de software. Alguns foram criados especificamente para projeto de software e outros adaptados de modelos de gerência de projetos. Alguns modelos de desenvolvimento incluem elementos de gerenciamento e vice-versa. Em decorrência disso, podem existir lacunas num projeto que executa um processo incompleto Algumas organizações adotam processos complementares, de forma a preencher essas lacunas.

Definição de modelo de processo e processo de software

Um modelo de processo é uma abstração de um processo (Sommerville, 2003, p. 36). Esses modelos representam as abordagens utilizadas no desenvolvimento de software dentro das organizações. Com base nesses modelos, diversos processos foram propostos para o desenvolvimento de software com a finalidade de se construir um produto melhor, de menor custo e mais rapidamente.

Um processo de desenvolvimento de software consiste num conjunto de atividades e resultados associados que geram um software (Sommerville, 2003, p. 7). Em geral, os processos de desenvolvimento têm como foco os aspectos técnicos, como especificação, desenvolvimento, validação e evolução do software e devem prover transparência e flexibilidade para facilitar o gerenciamento do projeto.

O processo adotado por uma organização também é uma abstração em relação ao processo executado num determinado projeto. Em geral, o processo da organização é adaptado de acordo com as necessidades específicas do projeto.

Importância do gerenciamento de projetos

Existe a necessidade de gerenciar o processo de desenvolvimento de software através de modelos, processos, atividades e ferramentas específicos. O desenvolvimento de um software ganha sentido no contexto de um negócio e de uma organização. É importante alinhar os requisitos de negócio com o produto de software e gerenciar as atividades de desenvolvimento, verificando prazo, custo e qualidade para que o projeto não termine em fracasso do ponto de vista do negócio (Sommerville, 2003, p. 60).

Os processos de desenvolvimento podem incluir atividades de gerenciamento, tal como o Processo Unificado (Rational, 2001), mas existem modelos e processos específicos para gerenciamento de projetos. É possível adotar uma combinação de processos complementares de acordo com as necessidades do projeto e da organização.

A estimação de software é importante para o gerenciamento de um projeto. Decisões como o cancelamento de um projeto podem ser tomadas com base em estimativas de custo e prazo necessários para desenvolver um determinado sistema de software. Estimativas adequadas resultam em decisões gerenciais acertadas, enquanto estimativas irreais causam prejuízo.

Além disso, dados do esforço real comparado com o esforço estimado fornecem uma importante ferramenta para ajuste das estimativas do projeto corrente e nos projetos futuros. A experiência e os dados agregados através desta comparação permitem estimar as atividades futuras com maior acurácia e atuar mitigando riscos de descumprimento de prazos acordados. Para isso, o gerente deve possuir os registros organizados das atividades concluídas.

Classificação dos modelos em relação à burocracia e à iteratividade

A estimação deve considerar o quanto o processo onera as atividades de desenvolvimento. Quanto mais atividades extras, documentação e rigor forem exigidos, maior será o fator de ajuste necessário para as estimativas.

Este estudo considera modelos mais burocráticos e com maior rigor como modelos tradicionais. Modelos com pouca burocracia, também chamados de empíricos, incluem os modelos de processos ágeis.

Kroll (2006) classifica alguns modelos num gráficos cujo eixo horizontal é o grau de disciplina adotado e o eixo vertical o nível de iteratividade. Na Figura 2, o autor posiciona o modelo de maturidade de processo CMM com grau elevado de burocracia e baixa iteratividade, enquanto os modelos ágeis com pouca burocracia e alta iteratividade. O CMMI, uma evolução do CMM, é mais iterativo e menos burocrático. Já os processos ágeis são bastante iterativos e muito pouco burocráticos.

Figura 2 – Grau de burocracia de processos tradicionais (Kroll, 2006, p. 36).

]1 Figura 2 – Grau de burocracia de processos tradicionais (Kroll, 2006, p. 36).

A Figura 3 apresenta a mesma ideia, incluindo agora o Processo Unificado. Devido a suas características de adaptação, o Processo Unificado abrange uma grande faixa do gráfico. Dependendo do projeto, ele pode ser adaptado para ser mais ou menos iterativo e disciplinado.

Figura 3 – Grau de burocracia dos processos ágeis (Kroll, 2006, p. 45).

]2 Figura 3 – Grau de burocracia dos processos ágeis (Kroll, 2006, p. 45).

Modelos de desenvolvimento e gerenciamento de software

Os modelos de desenvolvimento de software são abstrações das abordagens de desenvolvimento utilizadas nas organizações. Eles podem ser aplicados em diferentes processos individualmente, combinados e com variações.

Os modelos afetam diretamente a forma como o projeto é gerenciado. Os modelos iterativos, por exemplo, definem que haverá atividades de planejamento em cada iteração ao longo do desenvolvimento.

A compreensão dos princípios, benefícios e desvantagens desses modelos auxilia no desenvolvimento e na estimação de um software ao fornecer uma visão geral da abordagem utilizada no projeto.

Modelos incrementais

Os modelos incrementais englobam os modelos de desenvolvimento cuja constituição é de pequenos ciclos de desenvolvimento realizados de forma iterativa, ou seja, a cada ciclo novos incrementos são adicionados no software (Pressman, 2006, p. 40), que ganha funcionalidades no decorrer do projeto. Em cada iteração é produzida uma versão parcial funcional do software.

Este modelo possui vantagens em relação a um modelo sequencial de desenvolvimento. Os incrementos podem ser planejados para gerir os riscos técnicos, uma boa prática adotada por processos modernos (Campos, 2009). Ele também absorve melhor as mudanças nos requisitos, principalmente quando alguns deles ainda não foram claramente entendidos.

Dependendo das funcionalidades a serem desenvolvidas em cada incremento, atividades de gerenciamento devem realizar o respectivo planejamento, estimação e negociação dos requisitos para cada iteração.

Entretanto, o modelo incremental possui alguns problemas. Algumas funcionalidades dependem de outras, podendo ser interdependentes, por isso pode haver bloqueios no desenvolvimento. Além disso, alterações em requisitos já desenvolvidos invalidam o cronograma e as estimativas.

Modelos evolucionários

Nos modelos evolucionários o software é ajustado, melhorado e agrega novas funcionalidades, tornando-se mais completo, a cada ciclo de desenvolvimento (Pressman, 2006, p. 42). Sistemas de software precisam se adaptar com o passar do tempo. Não há como forçar um desenvolvimento linear até o produto final. A evolução gradual do produto é uma abordagem para solucionar esse problema.

Estes modelos também são iterativos, porém diferem dos modelos incrementais porque acomodam melhor situações onde apenas os requisitos básicos são entendidos, mas os detalhes somente serão conhecidos posteriormente.

Entretanto, nos modelos evolucionários é difícil estimar e planejar a quantidade de iterações necessárias para construir o produto completo, pois a maioria das técnicas de gestão e estimativa de projeto é baseada na disposição linear das atividades (Pressman, 2006, p.47).

A estimação e o planejamento em projetos que adotam o modelo evolucionário devem ser constantemente revisados na medida em que mudanças nos requisitos são detectadas. Na medida em que o projeto evolui, se houver gerenciamento adequado, os ajustes nas estimativas e o replanejamento provavelmente irão convergir para resultados mais próximos da realidade.

Modelos ágeis

O “Manifesto para o Desenvolvimento Ágil de Software” (Agile Manifesto, 2009), assinado no ano de 2001 por alguns proeminentes desenvolvedores de software, deu início um movimento emergente que busca formas de desenvolvimento de software mais ágeis. Este documento enfatiza alguns princípios já conhecidos com o objetivo de superar os desafios modernos do desenvolvimento de software (Pressman, 2006, p. 58).

Os princípios fundamentais dos modelos ágeis são:

  • indivíduos e interações em vez de processos e ferramentas;
  • softwares funcionando em vez de documentação abrangente;
  • colaboração do cliente ao invés de negociação de contratos;
  • resposta a modificações em vez de seguir um plano.

Os modelos ágeis procuram estabelecer apenas um conjunto mínimo de organização e disciplina, deixando as demais decisões a cargo da equipe. Há uma suposição de que uma equipe com experiência e diversidade de conhecimentos saberia como coordenar o seu trabalho e se auto-organizar, portanto qualquer tipo de burocracia inibiria a plena capacidade dos indivíduos. Os “agilistas” também defendem a tese que não basta apenas incluir alguns ajustes e boas práticas nos modelos tradicionais, é preciso livrar-se da “roupagem velha”.

O objetivo dos modelos ágeis em geral não é solucionar definitivamente os desafios da Engenharia de Software, mas prover o ambiente mais adequado para o desenvolvimento de software.

Além disso, os defensores e praticantes dos modelos ágeis, chamados “agilistas”, defendem a ideia de que os processos ágeis são os mais adequados para responder às altas taxas de mudanças de requisitos decorrentes da dinâmica dos negócios da atualidade.

Em contrapartida a todos os benefícios dos modelos ágeis, a correta aplicação dos diversos processos ágeis necessita de uma equipe experiente e de indivíduos capacitados e motivados. Além disso, projetos de softwares com alto grau de complexidade exigirão documentação detalhada. Tanto o cliente como os engenheiros de software podem criar barreiras técnicas e pessoais para aceitar o modo de trabalho estabelecido por alguns processos ágeis. Problemas nestes e em outros aspectos podem levar o projeto ao fracasso.

Os modelos ágeis enfatizam que a estimação das histórias de usuário e respectivas tarefas deve ser feita pela equipe de desenvolvimento, pois quem efetivamente executa o trabalho seria mais capacitado a estimá-lo do que pessoas que podem nem estar envolvidas com o projeto. Porém, delegar essa função exigirá organização, experiência e habilidade por parte da equipe. Além disso, os próprios agilistas reconhecem o fato de que desenvolvedores tendem a gerar estimativas otimistas, sendo necessário ao gerente ajustá-las posteriormente (Astels, 2002, p.70).

Em geral, adotar um modelo ágil não implica em restrições quanto à técnica de estimação, desde que a mesma atenda os princípios ágeis. Contudo, técnicas que envolvam a equipe como um todo e enfatizem a comunicação, tal como o Planning Poker (ver capítulo IV), são mais recomendadas.

Modelagem ágil

A modelagem ágil consiste em um conjunto de princípios consistentes com a filosofia dos modelos ágeis de desenvolvimento. Ela não é uma técnica ou método em si, mas estabelece uma filosofia para nortear a modelagem do sistema de software.

Adotar um processo ágil não significa que não haverá documentação, mas que esta deve ser produzida de acordo com os princípios ágeis de desenvolvimento. Ambler (2002) apresenta alguns princípios da modelagem ágil na tabela abaixo.

Tabela 1 – Princípios da Modelagem Ágil (Ambler, 2002)

Modelar com uma finalidade Somente criar diagramas, documentação e especificações se houver uma meta específica para isso.
Usar modelos múltiplos Escolher algumas das múltiplas formas de modelagem existentes que sejam necessárias e representativas.
Conservar apenas o que for necessário Atualizar os modelos no decorrer do projeto conforme as mudanças nos requisitos gera um trabalho considerável, então somente o que for realmente relevante deve ser conservado.
O conteúdo é mais importante que a representação A preocupação deve ser em transmitir a ideia e não com os formalismos de um modelo, isto é, as informações contidas nos artefatos devem ser apenas as suficientes para a situação atual.
Conhecer os modelos e ferramentas Saber como usar corretamente os modelos e ferramentas ajuda na decisão da forma como modelar um problema. Os diversos diagramas possuem características e limitações que são descartados conforme o uso.
Adaptar localmente A modelagem deve ser adaptada às necessidades do projeto e da equipe.

É possível aplicar esses princípios em qualquer modelo de desenvolvimento, mas uma contribuição que os processos ágeis trouxeram foi a ênfase em deixar de usar o “processo pelo processo”, ou seja, usar o processo apenas como um meio para atingir os objetivos da organização e não como um fim em si.

Prototipagem

A prototipagem é uma técnica que pode ser aplicada em modelos iterativos. Ela consiste em produzir uma iteração inicial do software baseada em requisitos de alto nível a fim de testar a viabilidade do projeto e a satisfação do cliente (Pressman, 2006, p. 42). Ela também serve como um mecanismo para identificação dos requisitos, pois permite uma verificação antecipada do que está sendo produzido.

Tudo o que foi produzido deveria ser descartado, pois a construção inicial rápida é geralmente desorganizada e sem qualidade. O custo de corrigir as funcionalidades e a arquitetura de um protótipo pode superar um novo desenvolvimento. A linguagem de programação e as ferramentas de prototipagem podem não ser ideais para o ambiente de produção. Entretanto, a perda pode ser minimizada incluindo o descarte no planejamento.

Existem riscos nesta abordagem. O cliente pode não entender que o protótipo deve ser descartado. Além disso, partes do sistema construídas de forma ineficiente podem permanecer no produto final.

A prototipagem aumenta a qualidade das estimativas quando ela atinge o objetivo de esclarecer os requisitos. Esta técnica é importante quando o domínio é complexo ou há dificuldades de comunicação com os usuários.

Processos de desenvolvimento de software

Modelo Waterfall

O modelo Waterfall é um modelo sequencial (ver Figura 4) de desenvolvimento que, em tese, funcionaria bem quando os requisitos fossem bem conhecidos e poucas mudanças fossem esperadas.

Figura 4 - Adaptado de Pressman (2006, p. 39).

]3 Figura 4 – Adaptado de Pressman (2006, p. 39).

Esse modelo é criticado por apresentar alguns problemas (Pressman, 2006, p. 39). Primeiramente, projetos reais raramente são sequenciais. Ajustes realizados gerariam um tipo de iteração confusa em meio às fases do modelo. Além disso, os requisitos definidos com antecedência sofrerão mudanças difíceis de absorver. Por último, o cliente somente recebe algo executável ao fim do ciclo. Pressman cita o trabalho de Bradac, que verificou que a linearidade deste modelo leva a bloqueios frequentes, ou seja, todos os participantes do projeto precisam esperar todos os demais completarem a fase atual antes de iniciar a próxima fase.

O gerenciamento de um projeto com o modelo Waterfall é mais difícil que em outros modelos. Como o planejamento, que inclui a estimação, é realizada apenas no início, não há muitos pontos de verificação e ajuste. O ajuste das estimativas exigiria atividades de planejamento durante o projeto, o que não é previsto no modelo.

Modelo Spiral

O modelo Spiral é um modelo orientado a riscos cujas iterações iniciais consistem em modelos de papel ou protótipos do software (Pressman, 2006, p. 44). Nas iterações posteriores são produzidas versões do sistema cada vez com mais funcionalidades. Um replanejamento é realizado a cada iteração levando em conta o retorno obtido do cliente.

Esse modelo é um dos mais adaptáveis e gerenciáveis, pois permite absorver com mais facilidade as mudanças nos requisitos de software ao longo do tempo devido à sua natureza iterativa e incremental. Além disso, as iterações podem ser estendidas além da entrega do produto final, incluindo novas versões do produto, finalizando apenas quando o produto for retirado de uso.

Processo Unificado

Segundo Kroll (2003, p. 32), o Processo Unificado é uma abordagem iterativa, centrada na arquitetura e dirigida por casos de uso. Este processo de gerenciamento e desenvolvimento de software foi uma tentativa de combinar as melhores características dos modelos de desenvolvimento (Pressman, 2006, p. 51).

O Processo Unificado enfatiza boas práticas de desenvolvimento (Kroll, 2003, p. 151), o que pode aumentar a qualidade das estimativas. Mitigar os riscos arquiteturais considerados mais impactantes o mais cedo possível através de provas de conceito, por exemplo, ajuda na compreensão do tamanho real do problema. Dessa forma, evita-se a falsa impressão do bom andamento do projeto enquanto os maiores desafios são deixados por último, os quais provavelmente irão invalidar qualquer estimativa. Além disso, se os riscos forem difíceis de superar, o custo de cancelamento do projeto não é tão grande como em fases mais avançadas.

Na verdade, esse processo funciona como um framework que permite a composição de processos específicos. Ele define um conjunto de atividades e produtos de trabalho que podem ser incluídos no processo de uma organização, de acordo com suas necessidades e de seus projetos. As atividades e os produtos de trabalho podem variar em quantidade, tamanho e detalhamento conforme o nível de gerenciamento desejado, além de outros fatores. O grau de burocracia pode ser ajustado de acordo com as necessidades do projeto.

O Processo Unificado pode ser adotado em pequenos e grandes projetos. Kroll (2003, p. 88) descreve aplicações do processo em projeto de apenas uma pessoa até projetos distribuídos com centenas de desenvolvedores, sendo o nível de burocracia em cada tipo de projeto compatível com a necessidade.

Extreme Programming

Beck (1999) publicou um trabalho que deu origem ao Extreme Programming (XP), um processo que utiliza uma abordagem de desenvolvimento orientada a objetos, iterativa e incremental (Novak, 2002). Ele é composto algumas fases que ocorrem a cada iteração (Pressman, 2006, p. 63).

Figura 5 - Adaptado de Presman (2006, p. 64)

]4 Figura 5 – Adaptado de Presman (2006, p. 64)

Na fase de planejamento cria-se um conjunto de histórias escritas pelo cliente em cartões de indexação, incluindo um valor associado ao negócio. O custo de cada história é definido com base nas avaliações dos desenvolvedores, conforme os princípios do modelo ágil. Algumas histórias são selecionadas para serem desenvolvidas na iteração atual.

A fase de design tem por objetivo criar uma representação simples das histórias que serão desenvolvidas na iteração. Utilizam-se preferencialmente cartões CRC (Classe- Responsabilidade-Colaborador), o único produto de trabalho que faz parte do processo. Cada história de usuário deve ter pelo menos um teste de aceitação para cada cenário identificado. O teste de aceitação de uma história de usuário tem por objetivo demonstrar que o comportamento do sistema corresponde ao esperado pelo usuário.

Durante a fase de codificação, a recomendação é não começar desenvolvendo as funcionalidades do sistema e sim codificando testes unitários para o que será desenvolvido. A codificação é realizada com a recomendação da programação em pares, onde duas pessoas trabalham juntas numa estação de trabalho. O ideal seria que, ao final de cada dia, o código produzido por cada par fosse integrado aos demais na estratégia conhecida como integração contínua.

O Extreme Programming incentiva a refatoração, ou seja, o processo de modificar um sistema de tal modo que ele não altere o comportamento externo do código, mas melhore a qualidade interna do software através de revisões arquiteturais, melhoria de desempenho, alterações no código para aumentar a clareza, entre outros (Astels, 2002, p. 149). É um modo disciplinado de modificar e simplificar o projeto que minimiza as chances de introdução de defeitos. Isso pode ser feito porque os testes automatizados garantem que as funcionalidades do sistema continuem consistentes.

O acompanhamento do progresso de desenvolvimento é realizado através dos testes de aceitação automatizados, embora não se descarte os testes de aceitação do usuário na entrega de uma versão. Dessa forma, o progresso é medido de acordo com uma visão aproximada à que o usuário possui sobre as funcionalidades que ele espera. Isso facilita o alinhamento dos objetivos do usuário com aqueles da equipe de desenvolvimento.

Scrum

O Scrum é um processo ágil de gerenciamento de projetos criado por Jeff Sutherland e Ken Schwaber na década de 90 (Schwaber, 2008). Ele é um processo empírico para desenvolvimento de produtos, isto é, não é restrito ao desenvolvimento de software, podendo ser aplicado em qualquer tipo de projeto cujas características do produto façam com que seu desenvolvimento não seja completamente previsível. Para que seja possível utilizar o Scrum, a equipe deve possuir todas as habilidades necessárias para executar as tarefas do projeto.

O Scrum foi desenvolvido sobre os pilares da transparência, onde os aspectos que afetam os resultados são visíveis para aqueles que gerenciam os resultados, da inspeção, onde os diversos aspectos do processo devem ser inspecionados com uma frequência suficiente para que variações inaceitáveis no processo possam ser detectadas, e da adaptação, pois se um ou mais aspectos do processo estão fora dos limites e o produto resultante for inaceitável, o gerente do projeto deverá ajustar o processo ou o material sendo processado o mais rápido possível para minimizar desvios posteriores.

Esses pilares procuram facilitar o gerenciamento do projeto. Os riscos podem ser mitigados assim que surgem e adaptações realizadas sempre que necessário. A flexibilidade evita que o processo torne-se uma obstrução para que a equipe atenda as necessidades imediatas do negócio.

Existem apenas três papéis que os membros de uma equipe Scrum podem assumir. O Scrum Master é responsável por garantir que o processo seja compreendido e seguido, como um gerente de projeto, o Product Owner por maximizar o valor do trabalho que a equipe desenvolve, representando o cliente, priorizando e explicando as funcionalidades, e o Time é todo o pessoal que executa efetivamente o trabalho.

O Scrum Master é responsável por manter estimativas atualizadas do projeto. As estimativas do projeto como um todo e da iteração atual são parte importante dos pilares acima descritos, pois elas são geradas com base na inspeção, possibilitam a transparência e são base para a adaptação necessária.

O Scrum define apenas quatro produtos de trabalho: o Product Backlog, que consiste em uma lista dos requisitos do produto (histórias de usuário, por exemplo), podendo ser alterado a qualquer momento do projeto; o Burndown da Release, um gráfico que mostra a soma das estimativas de trabalho restantes do Product Backlog ao longo do tempo; o Sprint Backlog, uma lista de tarefas que a equipe deve cumprir para gerar o próximo incremento do produto; e o Burndown da Sprint, um gráfico da quantidade de trabalho restante da iteração atual (sprint).

Os gráficos de burndown fornecem as estimativas atualizadas do projeto. Eles são gerados a partir do backlog e da composição de dados estimados e coletados da velocidade da equipe em cada atividade ou história de usuário. Através desses gráficos o gerente pode responder a qualquer momento sobre o estado da iteração (sprint) e do projeto (release). Porém o gráfico geral do release nem sempre é produzido, pois as histórias de usuário das próximas iterações podem sofrer mudanças drásticas.

As iterações do Scrum são divididas em seis fases, descritas na Tabela 2.

Tabela 2 – Princípios da Modelagem Ágil (Schwaber, 2008)

Reunião de planejamento da release Tem o propósito de estabelecer um plano e metas para a iteração que está começando. Nessa reunião o backlog inicial do release é criado.
Sprint É a iteração em si, que gera um novo incremento do produto contendo a implementação dos requisitos elicitados através das histórias de usuário selecionadas. A indicação da duração é de uma até quatro semanas, dependendo do nível de experiência da equipe.
Reunião de planejamento do sprint Realização de planejamento da iteração.
Revisão da sprint O incremento é apresentado aos clientes para obter o feedback e outras informações necessárias ao planejamento do próximo sprint.
Retrospectiva do sprint A equipe se reúne para analisar as decisões e ações que cada um considera terem sido acertadas ou erradas, por exemplo, sobre ferramentas ou técnicas adotadas, a fim de melhorar o processo de desenvolvimento da equipe.
Daily Scrum Reunião rápida, com duração média de 15 minutos, onde cada membro da equipe expõe resumidamente o que está fazendo e se há alguma barreira a ser superada.

A estimação inicial geral e de cada iteração ocorre nas reuniões de planejamento, enquanto o controle e as atualizações das estimativas são feitos através dos gráficos de burndown.

Combinação de Extreme Programming e Scrum

Por serem processos ágeis, Scrum e a Extreme Programming compartilham de princípios comuns e podem ser usados em conjunto. Scrum é um processo de gerenciamento de projetos, enquanto a Extreme Programming é um processo de desenvolvimento de software. Esses dois tipos de processos geralmente não são excludentes. Kniberg (2006) descreve suas experiências com os processos combinados e afirma que não há conflito entre eles.

Essa combinação é um exemplo de um processo que engloba duas esferas necessárias para o desenvolvimento de um software. Processos de gerenciamento como o Scrum não definem aspectos específicos do desenvolvimento de software, enquanto processos de desenvolvimento como o XP o fazem.

Quando o processo de uma organização não aborda devidamente as áreas necessárias e restam lacunas a serem preenchidas, atividades necessárias podem deixar de ser executadas ou serem feitas empiricamente, de forma marginal ao processo e sem gerenciamento.

Test Driven Development

O Test Driven Development (TDD) é um processo de desenvolvimento de software orientado por casos de testes. A partir dos cenários de uso identificados para um sistema, codificam-se testes para cada um deles. Durante o desenvolvimento, escreve-se o código necessário para obter sucesso em cada teste. Por fim, melhora-se a arquitetura e o código em geral usando os testes para garantir que o funcionamento esperado não foi afetado (Koskela, 2008, p. 33).

Este processo procura alinhar o desenvolvimento com os requisitos de negócio através dos testes de aceitação, garantindo que o software atenderá as necessidades de negócio. Se os testes de aceitação refletem o comportamento esperado pelos usuários, então o critério de avaliação do software é o resultado da execução dos testes. Isso permite avaliar e acompanhar a qualidade do sistema de um ponto de vista semelhante ao do usuário, evitando que sejam empreendidos esforços em não conformidade com as necessidades de negócio.

O TDD pode melhorar a acurácia da estimação. Ela procura garantir que a equipe tenha o entendimento das funcionalidades através da criação precoce dos testes. Assim, como a equipe precisa que conhecer os requisitos para a criação dos testes, ela terá uma noção mais apurada do problema, o que pode levar a estimativas melhores.

Feature Driven Development

O Feature Driven Development (FDD) é um processo prático, iterativo e incremental de desenvolvimento de software orientado a objetos com foco nas características do sistema. Uma característica “é uma função valorizada pelo cliente que pode ser implementada em duas semanas ou menos” (Pressman, 2009, p. 71). A cada iteração de incremento do software algumas características que agregam valor ao produto são estimadas, selecionadas e então desenvolvidas de forma que o resultado do respectivo teste passe a ser de sucesso.

O objetivo deste processo é valorizar o produto focando as características que o cliente necessita. O foco em características facilita a compreensão do produto pelo cliente e no entendimento deste com a equipe de desenvolvimento.

O FDD pode dificultar a atividade de estimação quando as características são muito abstratas em relação ao software. A visão do produto através de características pode ser mais compreensível do ponto de vista do usuário, mas para a equipe de desenvolvimento é um desafio tentar prever o esforço de desenvolvimento necessário para uma característica descrita em alto nível.

Conclusão

Conhecer e entender os diferentes modelos e processos de desenvolvimento de software e gerenciamento de projetos é importante para uma estimação adequada. Os processos e modelos fornecem abordagens práticas para o desafio de desenvolver software de acordo com as reais necessidades do cliente.

Há uma tendência dos processos modernos em buscar flexibilidade, menor burocracia e manter o foco no produto de negócio. Isso significa diminuir o tempo que a equipe gasta com atividades desnecessárias ou sem sentido de modo a não encarecer o produto e tornar possível que a organização coloque seu foco no negócio e não em processos, técnicas ou tecnologias.

O próximo capítulo apresenta noções de estimativas, além de técnicas e modelos de estimação. As práticas e abordagens dos processos de software apresentadas neste capítulo e as noções de engenharia de requisitos apresentadas no capítulo anterior fornecerão uma base para a correta compreensão da atividade de estimação e de sua execução dentro dos processos de desenvolvimento.

Noções de Engenharia de Requisitos

Este artigo é o Capítulo II da minha monografia de Especialização em Engenharia de Software. Embora seja um referencial teórico e não acrescente nada de novo, espero que o possa ser útil de alguma forma para o leitor.

Introdução

Este capítulo apresenta noções sobre a engenharia de requisitos. Os requisitos são a base para a atividade de estimação do software, pois fornecem a abstração necessária do problema para que os engenheiros software executem a devida análise do problema.

No contexto de uma organização, um requisito normalmente tem sua origem em uma necessidade de negócio. A ideia de se desenvolver um software surge quando há um conjunto de necessidades específicas a serem atendidas, as quais devem ser traduzidas em requisitos.

Este processo inclui uma série de dificuldades e desafios. Problemas de comunicação, entendimento e complexidade são alguns dos fatores que contribuem para isso.

Os próximos tópicos apresentam diferentes abordagens e conceitos sobre os requisitos que causam impacto direto na estimação de um software.

Definição de requisito

Sommerville (2003, p. 82) identifica duas visões distintas sobre o termo requisito. Este pode ser “uma visão abstrata, de alto nível, de uma função que o sistema deve fornecer ou de uma restrição do sistema” ou, em outro extremo, “uma definição detalhada, matematicamente formal, de uma função do sistema”.

O autor ainda destaca diferentes níveis de detalhamento dos requisitos:

  • Requisitos do usuário: declarações em linguagem natural sobre as funções que o sistema deve fornecer.
  • Requisitos do sistema: detalhamentos das funções e restrições do sistema, podendo ser usados no contrato de desenvolvimento de software.
  • Especificação de projeto de software: descrição abstrata do projeto de software, acrescentando mais detalhes sobre a solução aos requisitos do sistema.

Os requisitos são a base para o desenvolvimento de uma solução para o problema. Com o entendimento dos requisitos num determinado momento do projeto se constrói o respectivo modelo de análise. A estimação do software pode ser feita com nesse modelo, que contém os elementos da solução do problema que serão desenvolvidos.

O nível de detalhamento e a maneira formal ou abstrata de especificação dos requisitos é uma escolha a ser feita de acordo com o projeto. Porém, cedo ou tarde, uma especificação matematicamente formal dos requisitos terá que ser criada como parte do programa de computador, seja através de documentação ou diretamente no código-fonte. A compreensão sobre o problema e a experiência da equipe no tipo de problema são critérios que podem definir essa questão. A necessidade de estimar em maior ou menor grau de detalhe também influencia na decisão.

Tipos de requisitos

Os requisitos podem ser classificados em funcionais e não funcionais (Sommerville, 2003, p. 83). Requisitos funcionais são aqueles ligados diretamente às funções ou reações que o sistema deve apresentar. Requisitos não funcionais são restrições impostas ao funcionamento do sistema, tais como restrições de tempo, de orçamento, do processo de desenvolvimento, políticas organizacionais, padrões que devem ser adotados, entre outros. Existem ainda requisitos de domínio, ou seja, aqueles originados do domínio da aplicação, podendo estes ser funcionais ou não funcionais.

A distinção entre os tipos de requisitos é relevante no sentido de contribuir para o gerenciamento de prioridades. Se não há tempo ou recursos suficientes para desenvolver todos os requisitos, geralmente priorizam-se os requisitos funcionais.

Os requisitos funcionais são os componentes principais das estimativas. Em geral, eles são mapeados diretamente a funcionalidades ou elementos do sistema de software. Em decorrência disso, a qualidade dos requisitos funcionais tem grande efeito sobre a qualidade das estimativas.

Requisitos não funcionais afetam as estimativas em graus diferentes, dependendo da natureza de cada um. As técnicas e modelos de estimação possuem fatores de ajuste e calibragem que incluem restrições técnicas, complexidade do problema, ferramentas de desenvolvimento, etc. Portanto, esses tipos de requisitos também afetam a qualidade das estimativas.

Mutabilidade dos requisitos

Os requisitos de software não podem ser definidos estaticamente no decorrer do projeto. A definição de um requisito representa um instantâneo, mas não as mudanças que ele sofre no decorrer do tempo. Pressman (2006, p. 39) afirma que “hoje em dia, o trabalho de software é em ritmo rápido e sujeito a uma torrente sem fim de modificações (de características, funções e conteúdo da informação)”.

McConnell (1996) afirma que, em média, os requisitos mudam 25% desde a fase em que deveriam estar definidos até a primeira versão do software. Essa estimativa demonstra a natureza mutante dos requisitos e consiste num dos motivos pelos quais o software e as estimativas também não são estáticos.

Engenharia de requisitos

A engenharia de requisitos é uma atividade da Engenharia de Software que busca o entendimento do sistema a ser construído (Pressman, 2006, p. 117). Ela não é uma ciência exata, mas oferece uma abordagem sólida para enfrentar os desafios de comunicação e complexidade encontrados no início do projeto de software.

Além disso, os requisitos devem ser identificados e gerenciados no decorrer do projeto de forma que reflitam as reais necessidades dos clientes. O entendimento do sistema deve aumentar com o passar do tempo e os requisitos devem refletir este aprofundamento.

Pressman (2006, p. 117) afirma que é importante identificar corretamente os requisitos durante as fases de análise e modelagem. Ele contradiz os autores que defendem a prática de iniciar o desenvolvimento do software precipitadamente. Segundo esses autores, não valeria a pena gastar tempo com os requisitos iniciais devido às inevitáveis mudanças, de modo que as iterações iniciais tornariam as necessidades do cliente mais claras. Pressman afirma que a complexidade que surge no decorrer do projeto logo derruba esses argumentos.

Pressman (2006, p. 118) define as seguintes fases para a atividade de engenharia de requisitos:

  • Concepção: fase inicial onde os engenheiros perguntam uma séria de questões livres de contexto para estabelecer um entendimento básico do problema e alguns fatores que influenciam no projeto.
  • Levantamento: são feitas perguntas específicas sobre os objetivos do sistema, a meta a ser atingida, como o software será usado no dia-a-dia e assim por diante. Nesta fase, podem surgir problemas como:
    • Escopo: os limites do sistema não estão estabelecidos ou o cliente entra em detalhes técnicos desnecessários que dificultam o entendimento dos requisitos ao invés de esclarecê-los.
    • Entendimento: o cliente e os usuários não tem certeza do que é necessário, tem pouca compreensão do ambiente computacional, não tem entendimento do domínio do problema, omitem informações, apresentam necessidades conflitantes e assim por diante.
    • Volatilidade (ou mutabilidade): os requisitos mudam ao longo do tempo.
  • Elaboração: procuram-se eliminar os problemas das fases anteriores, tentando estabelecer um modelo refinado dos requisitos que consiste num modelo de análise e contém cenários de uso e a descrição de como o usuário irá interagir com o sistema.
  • Negociação: os requisitos propostos pelo cliente ou pelos usuários que são conflitantes, desnecessários, de alto risco ou inatingíveis por características do projeto, domínio ou por outro motivo precisam ser discutidos e negociados com o cliente desde o início do projeto, em cada iteração.
  • Validação: uma análise da qualidade dos requisitos é realizada para garantir que não existem mais ambiguidades, inconsistências, omissões e erros através de uma revisão técnicas pelos engenheiros, clientes, usuários e outros interessados.

A estimação relaciona-se diretamente em como as atividades de engenharia de requisitos são realizadas. Quanto mais cedo forem geradas estimativas, menos detalhes serão obtidos e a margem de erro é maior. Quanto melhores habilidades e maior a experiência dos envolvidos no processo de elicitação de requisitos, maiores são as chances das estimativas serem confiáveis.

Gestão de requisitos

Os requisitos mudam e precisam ser monitorados, rastreados e gerenciados. A engenharia de requisitos é uma atividade executada durante todo o projeto. A princípio ela é mais intensamente executada para que todos os requisitos sejam elicitados, mas provavelmente diminuirá de intensidade no decorrer do tempo na medida em os requisitos forem mais conhecidos, desenvolvidos e atenderem às expectativas dos usuários.

Porém, cada mudança de requisito pode afetar vários elementos do projeto, tais como outros requisitos, funcionalidades e interfaces do sistema. A fim de gerenciar o encadeamento de mudanças utilizam-se técnicas de rastreabilidade, ou seja, identificação dos relacionamentos do requisito com os demais elementos do projeto.

Pressman (2006, p. 121) lista alguns tipos de tabelas de rastreabilidade que podem ser usadas quando há preocupação em identificar o impacto da mudança em um determinado requisito:

  • Tabela de rastreamento de características: mostra relação do requisito com características importantes do sistema.
  • Tabela de rastreamento de fontes: identifica a fonte de cada requisito.
  • Tabela de rastreamento de dependência: relaciona os requisitos uns com os outros.
  • Tabela de rastreamento de interfaces: mostra relação do requisito com as interfaces internas e externas do sistema.

Após a mudança em um requisito e a devida atualização dos elementos afetados, as estimativas de todos esses elementos também são afetadas e devem ser atualizadas. Isso permite analisar o impacto e a viabilidade da mudança no contexto do projeto.

Atividades da engenharia de requisitos

Durante o início do processo de engenharia de requisitos, na fase de concepção, Pressman (2006, p. 122) indica alguns passos necessários para colocar o projeto em andamento:

  • Identificação dos interessados: um interessado é “quem quer que se beneficie de modo direto ou indireto do sistema que está sendo desenvolvido” (Pressman, 206, p. 122), tais como gerentes de negócio, gerentes de produto, engenheiros de software, engenheiros de suporte. Essas pessoas fornecerão entradas para os requisitos de usuário.
  • Reconhecimento de diversos pontos de vista: os requisitos de usuário iniciais são explorados através de questões e comparações dos diversos pontos de vista dos interessados e precisam ser compostos para formar um conjunto consistente de requisitos.
  • Trabalho em busca de colaboração: é necessário buscar a colaboração de todos os interessados no sistema, evitando conflitos entre as partes.
  • Formulação das questões iniciais: definir questões livres de contexto para o cliente e os demais interessados no projeto.

Depois disso, na fase de levantamento de requisitos formais, Pressman (2006, p. 124) fornece as seguintes abordagens:

  • Coleta colaborativa de requisitos: os interessados no projeto se reúnem e discutem a necessidade e a justificativa do novo produto, cada um expõe uma lista de objetivos que consideram importantes para o sistema, os quais são discutidos e combinados para formar uma lista geral, que então seria usada para derivar os requisitos do sistema.
  • Implantação da função de qualidade: a Quality Function Deployment (QFD) é uma técnica que procura traduzir as necessidades dos clientes em requisitos que enfatizam o que possui mais valor para o cliente. Esta técnica cobre todo o processo de Engenharia de Software, mas é muito bem aplicada na engenharia de requisitos. Um ponto importante é sua classificação de requisitos em:
    • Requisitos formais: refletem objetivos e metas para o produto que garantem a satisfação do cliente.
    • Requisitos esperados: requisitos implícitos no produto, que o cliente pode não fazer deixar óbvio, mas sua falta geraria insatisfação.
    • Requisitos excitantes: requisitos que vão além das expectativas do cliente.
  • Cenários de usuário: consiste na criação de um conjunto de cenários de uso que descrevam como o software será usado.

A estimação do software depende do resultado das atividades de engenharia de requisitos. Alguns produtos de trabalho comumente gerados e que podem ser usados na estimação são:

  • lista de clientes, usuários e outros interessados;
  • descrição do ambiente técnico do sistema;
  • lista dos requisitos e restrições;
  • conjunto de cenários de uso;
  • protótipo desenvolvido para definir melhor os requisitos.

Modelo de análise

Segundo Pressman (2006, p. 134), “o modelo de análise é um instantâneo dos requisitos em um determinado tempo”. Quando é necessário obter uma posição atualizada do projeto ele deve ser atualizado para refletir as mudanças dos requisitos. Um modelo de análise inicial correto fornece uma base sólida para o restante do projeto, embora mudanças sejam certas.

O modelo de análise pode se basear em diferentes elementos, tais como cenários, classes, comportamentos e fluxo. Linguagens como a UML (Unified Modeling Language), com seus diversos diagramas, são utilizadas para descrever os diferentes elemento e aspectos do sistema (Pressman, 2006, p. 153).

Em um processo de desenvolvimento tradicional, o modelo de análise é o ponto de partida para a tarefa de estimação do projeto de software. Os elementos da análise servem como entrada para os modelos e técnicas de estimação.

Histórias de usuário

Os modelos ágeis utilizam histórias de usuário para capturar as necessidades dos clientes em um projeto de software. Uma história de usuário é uma descrição em primeira pessoa e em alto nível de uma ação que o usuário efetua no sistema (Cohn, 2004).

Histórias de usuário são escritas em primeira pessoa e em linguagem simples com a finalidade de melhorar o entendimento entre a equipe de desenvolvimento e o cliente, pois uma das maiores barreiras no entendimento do problema é na comunicação (Cohn, 2004). Portanto, ao invés de documentos técnicos e formais, as histórias de usuário enfatizam a forma verbal de comunicação.

Ao escrever uma história de usuário evitam-se detalhes considerados desnecessários e inconvenientes (Koskella, 2008, p. 326). Isso significa que ela deve ser escrita em poucas palavras e evitando abranger mais de uma funcionalidade. Em alguns casos, quando uma funcionalidade é complexa por natureza, várias histórias de usuário podem refletir cenários específicos dela. Além disso, uma história muito detalhada poderia prescrever tecnicamente uma solução, isto é, influenciando demasiadamente em como o desenvolvedor irá fazer sua implementação.

Backlog

O backlog é uma lista do que ainda é necessário fazer para concluir o produto ou uma iteração (Schwaber, 2004). Em geral, o backlog é composto pelo conjunto de histórias de usuário necessárias para concluir o produto ou pelo conjunto de atividades necessárias para concluir as histórias de usuário selecionadas e estimadas para a iteração. Schwaber (2004) define os dois tipos de backlog:

  • Backlog do produto: a lista de histórias necessárias para concluir o produto, incluindo as estimativas para cada uma delas.
  • Backlog do sprint: a lista de tarefas necessárias para completar as histórias de usuário selecionadas para a entrega do próximo incremento funcional do produto.

O backlog pode ser mantido em ordem de importância ou prioridade para facilitar o planejamento das próximas iterações e o controle da iteração atual.

As estimativas de conclusão da iteração, conclusão do produto e velocidade da equipe são derivadas do gerenciamento do backlog. O gerente ajusta as estimativas na medida em que os dados reais de tempo são coletados durante a execução das atividades.

Conclusão

A engenharia de requisitos propõe abordagens para lidar com a inevitável dificuldade em definir os requisitos de um sistema de software e construir e manter o modelo de análise, ou seja, a definição do que será construído.

Entretanto, é necessário talento, experiência e esforço para obter requisitos adequados nesse processo devido a barreiras relacionadas à comunicação, escopo e mutabilidade.

Com lista inicial de requisitos, pode ser realizada a estimação inicial do software e então criado um cronograma baseado nas funcionalidades.

Porém, o processo de desenvolvimento de software executado no projeto afetará o cronograma. O projeto não é constituído apenas de tarefas de programação sequencialmente executadas. Cada processo é composto de atividades de desenvolvimento e gerenciamento que incluem aspectos além do software em si, demandando atividades extras, dividindo o desenvolvimento em fases e iterações, fornecendo atividades de ajuste e artefatos de saída que permitam o gerenciamento do projeto. Portanto, a atividade de estimação deve considerar o processo para ajustar as estimativas geradas.

No próximo capítulo são apresentados modelos de processos de desenvolvimento de software e gerenciamento de projetos que foram propostos para organizar o desenvolvimento de software.

Noções de Engenharia de Software

Este artigo é o Capítulo I da minha monografia de Especialização em Engenharia de Software. Embora seja um referencial teórico e não acrescente nada de novo, espero que o possa ser útil de alguma forma para o leitor.

Introdução

Neste capítulo são apresentadas definições de termos utilizados neste estudo com o intuito de nivelar o entendimento sobre os mesmos. Embora tais conceitos possam ser considerados de senso comum, é certo que existem visões distintas e conflitantes.

Os próximos tópicos revisarão alguns conceitos da Engenharia de Software pertinentes ao tema.

Definição de aplicativo de software

Aplicativos de software são “programas isolados que resolvem uma necessidade específica do negócio” (Pressman, 2006, p. 4). Exemplos disso são softwares que processam dados comerciais ou técnicos que facilitam as operações e a gestão de um negócio. Além do código-fonte, o software inclui toda a documentação e os dados necessários para que o programa funcione corretamente (Sommerville, 2003, p. 5).

Definição de Engenharia de Software

A Engenharia de Software é a disciplina que trata de todos os aspectos do desenvolvimento de um software, incluindo as atividades de engenharia de requisitos, os modelos de processos e os modelos e técnicas de estimação (Sommerville, 2003, p. 6-7).

Um aplicativo de software é desenvolvido através de um processo. Não é algo que se fabrica a partir de matéria prima, nem é montado a partir de partes menores. Segundo Pressman (2006, p. 4), o software apresenta esta característica especial em relação a outros tipos de produtos, ou seja: ele não é fabricado no sentido clássico, mas desenvolvido, passando por um processo de engenharia.

A Engenharia de Software fornece abordagens sólidas para aumentar as chances de que os objetivos de negócio sejam atingidos em termos de prazo, qualidade e funcionalidades. Segundo Campos (2009, p. 2), as organizações enfrentam hoje o desafio de desempenhar suas atividades de forma produtiva, com qualidade e cumprindo o planejamento estratégico. Portanto, o uso de uma abordagem adequada no desenvolvimento de um software para elicitação de requisitos, estimação, desenvolvimento e controle é fundamental para as organizações.

Definição de projeto de software

Um projeto consiste num empreendimento temporário, cujo objetivo é a criação de um produto ou prestação de um serviço. Um projeto de software consiste no desenvolvimento de um software, incluindo os artefatos relacionados.

Independente do modelo de processo adotado, o empreendimento de construção de um software envolve atividades de diversas áreas de conhecimento utilizadas em maior ou menor grau durante as fases do projeto, nos âmbitos de gerenciamento e desenvolvimento.

Figura 1 - Visão geral de um modelo iterativo (Rational, 2001)

Figura 1 – Visão geral de um modelo iterativo (Rational, 2001)

O Processo Unificado (Rational, 2001), por exemplo, classifica as atividades da Engenharia de Software em nove disciplinas, dentre as quais cinco são relacionadas diretamente ao produto de software e três ao controle e gerenciamento, isto é, atividades de suporte ao desenvolvimento (Figura 1). No decorrer do projeto, as disciplinas demonstram um maior ou menor grau de atividade e nota-se que o gerenciamento do projeto é a única disciplina utilizada com certa regularidade no decorrer do tempo.

As estimativas de software são o fundamento para o planejamento do projeto ao permitirem uma visão geral do esforço necessário para o desenvolvimento e de variáveis que influenciam o projeto positivamente ou negativamente, tais como a produtividade da equipe e a complexidade do domínio.

Noções sobre arquitetura de software

Antes do desenvolvimento de um software é necessário definir sua arquitetura. O projeto da arquitetura é realizado através da decomposição do software em componentes. A arquitetura descreve o papel dos componentes que compõem o software e o relacionamento eles (Sommerville, 2003, p. 182).

A arquitetura do software fornece um framework estrutural básico para o desenvolvimento do software. Os diversos componentes do sistema agrupam elementos similares, tal como objetos com comportamento semelhante, e facilitam a estruturação do software. Dessa forma, é possível determinar com facilidade quais partes do sistema são afetadas pela implementação ou alteração de uma funcionalidade, pois os tipos de componentes e objetos estarão previamente definidos.

A decomposição arquitetural fornece um ponto de partida para técnicas de estimação baseadas em objetos ou elementos do software. A estimação é possível ao contar os elementos de um componente e estimar cada componente dessa forma. A estimativa resultante tende a ter mais qualidade devido ao conhecimento do tipo de elemento do componente em relação a estimativas geradas sem uma arquitetura definida.

Além disso, a arquitetura influencia diretamente na complexidade do software (Pressman, 2006, p. 223). Quanto mais dependências compartilhadas de recursos, tal como banco de dados ou arquivos, e dependências entre os componentes que compõem o software, maior será a sua complexidade. Um grande número de interdependências faz com que qualquer alteração cause maiores impactos em outros componentes.

Através da arquitetura é possível analisar o impacto de modificações no software. Isso é feito considerando as dependências entre os componentes. Além disso, ao desenvolver uma nova funcionalidade, é mais fácil identificar com antecedência os elementos dos componentes que serão necessários desenvolver, modificar ou reusar.

A análise de impacto de alterações é importante para o ajuste das estimativas dos componentes afetados quando se deseja obter uma posição atualizada do projeto.

Barreiras do desenvolvimento e estimação de software

A atividade de estimação consiste em tentar antecipar o tamanho ou esforço de desenvolvimento de um produto abstrato. Existe uma série de desafios que fazem com que o software seja difícil de estimar e, consequentemente, o projeto difícil de planejar.

Por um lado, isso se deve a características intrínsecas ao software. Brooks (1987) afirma que, por definição, o software é complexo e irredutível, ou seja, não é possível simplificá-lo sem que haja perda de informação. Ele apresenta quatro características importantes que contribuem para isso, tornando o software essencialmente difícil de construir:

  • Complexidade: entidades de software são extremamente complexas para seu tamanho e não existem duas partes iguais no nível de algoritmo. Isso faz parte da natureza do software, não ocorrendo por acaso. A escalabilidade de um software, por exemplo, não consiste simplesmente em fazer suas partes maiores ou menores, diferentemente de construções físicas realizadas pelo homem.
  • Conformidade: apesar de existirem áreas onde pessoas lidam com alta complexidade, o software possui algumas complicações adicionais. Por exemplo, um físico lida com a complexidade do átomo, mas este possui uma interface “bem definida” pela natureza, ou seja, os átomos possuem uma conformidade. O software tem diversas interfaces diferentes definidas por diversas pessoas e geralmente há pouca ou nenhuma conformidade nestas definições.
  • Mutabilidade: o software parece estar sempre pressionado a mudar. Produtos fabricados como pontes, carros e máquinas também estão, mas geralmente eles são substituídos por novos modelos, não sendo modificados com a mesma facilidade de um software. Eles são produtos tangíveis, com escopo bem definido e o custo de modificações maiores é impeditivo. Um software, por ser abstrato e com baixos custos diretos para se mexer, muitas vezes sem aparentes consequências imediatas, sofre constantes mudanças. Além disso, a maioria das mudanças tem como objetivo fazer com que o software vá além de seus limites iniciais.
  • Invisibilidade ou intangibilidade: apesar de existirem interfaces e linguagens amigáveis, o software não pode ser visualizado através de imagens. Em geral, desenvolvedor e usuário não conseguem enxergar o software como um todo. Isso ocorre porque os usuários geralmente não compreendem as questões tecnológicas e os desenvolvedores não entendem todas as regras do negócio, além do que um software pode ser desenvolvido por diversos indivíduos especialistas em diferentes áreas. Portanto, como cliente e desenvolvedor não conseguem ter em mente o software por completo, as chances de erros aumentam.

A estimação é realizada com base numa abstração em forma de requisitos. Por definição, ela não pode ser exata ao considerar as características apresentadas acima, pois a estimativa é, na verdade, baseada numa ideia pré-concebida do software.

Mesmo medidas do produto final de software são subjetivas. Não existem métricas objetivas de tamanho, qualidade, eficiência, robustez, usabilidade e tantos outros aspectos. Mesmo o número de linhas de código ou caracteres do código fonte não possuem uma relação direta com as funcionalidades e características do software, embora muito esforço tenha sido empreendido em conseguir uma aproximação razoável. Isso implica em que qualquer comparação entre softwares, processos de desenvolvimento, técnicas estimação e de engenharia de requisitos somente podem ser realizadas através de critérios específicos e objetivos. Portanto, não é possível afirmar categoricamente que uma técnica, método ou modelo seja superior a qualquer outro.

Por outro lado, o fator humano acrescenta ainda mais dificuldades no desenvolvimento e na estimação de um software. Enquanto desenvolvedores e arquitetos pensam em nível técnico e funcional, os gerentes observam o cronograma e os custos. Não é tarefa fácil conciliar ambas as perspectivas, sendo um desafio alinhar os objetivos estratégicos de uma organização com os aspectos técnicos e abstratos de um produto de software.

Do ponto de vista de quem está gerenciando o projeto, prazo e cronograma são fundamentais para que decisões sejam tomadas e estratégias de negócio estabelecidas, portanto boas estimativas são necessárias. Isso pode ser um problema do ponto de vista da equipe de desenvolvimento, por exemplo, quando prazos arbitrários são definidos ou tempo e recursos disponíveis são tecnicamente insuficientes.

Portanto, tanto a natureza do software quanto os fatores humanos devem ser considerados na estimação. Da mesma forma, quando há alterações no contexto do projeto de software, tal como mudança nos requisitos, no domínio ou na equipe, as estimativas são afetadas e devem ser ajustadas.

Conclusão

Este capítulo definiu o tipo e a natureza da entidade de software, além de descrever brevemente alguns aspectos relacionados ao processo de desenvolvimento.

Sistemas de software são entidades complexas e difíceis de desenvolver. Por isso, a Engenharia de Software busca mitigar os riscos e diminuir as falhas em projetos de desenvolvimento software através de modelos de processos, técnicas e boas práticas.

Entretanto, a correta estimação de um software inclui compreender o que exatamente deve ser construído e como isso será realizado. Assim, os próximos capítulos apresentam abordagens da Engenharia de Software para a engenharia de requisitos e para o desenvolvimento e gerenciamento do projeto.

Problemas de compatibilidade de versões no Java: especificando a versão do JDK para compilação

Uma das preocupações ao compilarmos aplicações e bibliotecas em Java é que a versão usada para compilação seja compatível com a versão onde o código será executado.

Por exemplo, você pode ter o Java 7 instalado em seu computador de desenvolvimento. Se você gerar um jar e tentar executar no computador de um cliente com o Java 6 pode ocorrer um erro!

Compilação em modo de compatibilidade

A primeira solução para problemas com versões diferentes é configurar o compilador para compilar em modo de compatibilidade.

Mas há um problema: isso não garante que o código executá. A cada versão do Java, classes ganham novos métodos e novas classes são adicionadas. A compilação em modo compatibilidade irá suceder sem erros, mas ao executar as classes em versões anteriores do Java, ocorrerão erros de tempo de execução por falta dos métodos e classes que não existem nas APIs nativas naquela versão.

Um exemplo simples é o construtor da classe BigDecimal que recebe um inteiro. Ele foi adicionado no Java 5, mas um código que use esse construtor é compilado sem problemas em compatibilidade para Java 1.4. Obviamente, ao executar esse código num JRE 1.4 ocorrerá um erro fatal.

Especificando um JDK alternativo

Então temos a segunda solução, que nos traz garantia de funcionamento: compilar o código com a mesma versão do ambiente do cliente.

Isso não significa, entretanto, que precisamos excluir todas as demais versões do Java de nosso ambiente de desenvolvimento, muito menos que só poderemos trabalhar com uma única versão em todos os projetos.

É possível especificar uma versão alternativa do Java para cada projeto, seja no Eclipse, Ant ou Maven.

Para ver como instalar o JDK 7, consulte o artigo Instalando e Configurando o Java Development Kit 7 para Desenvolvimento.

Especificando a versão e o JDK no Maven

No pom.xml podemos configurar o maven-compiler-plugin da seguinte forma:

  • <source>: especifica a versão do Java em que está escrito o código-fonte.
  • <target>: especifica para qual versão do Java o compilador deve compilar o código.
  • <executable>: especifica qual compilador (javac) será usado.

Exemplo:

<!-- CONFIGURAR VERSÃO DO JAVA PARA 1.7 -->
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
            <configuration>
                <source>1.7</source>
                <target>1.7</target>
                <executable>C:\Program Files\Java\jdk1.7.0_45\bin\javac</executable>
            </configuration>
        </plugin>
    </plugins>
</build>

Veja a documentação aqui.

Configuração única para um grupo de projetos usando herança

Não é necessário ter a configuração acima em cada novo projeto. Você pode criar um parent pom e usar a herança para reaproveitar essa configuração em todos os seus projetos.

Veja como especificar o pai de um projeto:

<parent>
    <groupId>org.minhaempresa</groupId>
    <artifactId>meu-pom-principal</artifactId>
    <version>1.0.0</version>
</parent>

Configuração única para todos os ambientes

Um problema que pode ocorrer é que cada desenvolvedor tem uma instalação do Java em local diferente. Se houver um servidor de integração contínua, o problema é o mesmo. Como especificar o Java sem ter que ajustar o caminho em cada máquina?

Para resolver isso, podemos criar um perfil (profile) diretamente na configuração do Maven. Um perfil nada mais é que um conjunto de configurações que você pode ativar e desativar quando quiser. Se essa configuração for feita em cada instalação do Maven e o perfil for ativado por padrão, podemos especificar a versão do Java em cada local sem maiores dificuldades.

Primeiro, edite o seu arquivo settings.xml que fica na sua pasta de usuário ou então no diretório conf da instalação do Maven e adicione um perfil com uma propriedade especificando onde está o Java.

Exemplo:

<profiles>
    <profile>
        <id>compiler</id>
        <properties>
            <JDK7>C:\Program Files\Java\jdk1.7.0_45</JDK7>
            <JDK4>C:\Program Files\Java\jdk1.4</JDK4>
        </properties>
    </profile>
</profiles>

No código acima, definimos duas propriedades JDK7 e JDK4. Note que você pode definir quantas propriedades quiser.

Agora devemos ativar o perfil para todos os projetos que usem essa instalação do Maven, editando novamente o settings.xml e adicionando o seguinte trecho:

<activeProfiles>
    <activeProfile>compiler</activeProfile>
</activeProfiles>

Então, em seu projeto ou parent pom, use a propriedade definida assim:

<executable>${JDK7}/bin/javac</executable>

Definindo o JDK num projeto do Eclipse

Ao abrir o Eclipse, ele virá configurado com mesmo o JDK usado para executá-lo, ou seja, o que estiver configurado como padrão em seu computador. Todavia, você pode incluir na configuração do Eclipse quantas versões quiser, tanto do JDK (compilação) quanto do JRE (execução).

Incluindo uma instalação do Java no Eclipse

Primeiro, acesse o menu Window > Preferences... e vá até a configuração Java > Installed JREs.

01

Clique em Add....

02

Selecione a opção Standard VM e clique em Next >.

03

Preencha o campo JRE home digitando o diretório de instalação do Java que você quer adicionar. Ou clique em Directory... para procurar a pasta. O Eclipse irá preencher as demais informações para você.

04

Clique em Finish e a nova instalação será adicionada à lista.

05

Clique em OK.

Configurando o projeto para usar uma versão específica do Java

Clique com o botão direito em um projeto e acesse a opção Properties. Clique no item Java Build Path e vá até a aba Libraries.

06

Selecione o Java atualmente em uso e clique no botão Edit....

07

Selecione o item Alternate JRE, selecione a JRE ou JDK que você quer usar e clique em Finish.

08

Verifique se o Java mudou e clique em OK para concluir a configuração.

Talvez o Eclipse emita um aviso de que será necessário recompilar o projeto. Isso é normal, apenas confirme.

Note que para projetos que usam o plugin do Maven para o Eclipse (M2E), você não precisa fazer isso manualmente. Apenas adicione o JDK ao Eclipse, como descrito acima, e configure seu pom.xml. O plugin selecionará o Java mais adequado para o projeto automaticamente.

Especificando o JDK num build Ant

Caso você faça a compilação e empacotamento de seus projetos com scripts Ant, é possível especificar a versão de compilação para a task <javac> de uma forma muito simples. Basta definir o atributo executable, por exemplo:

<javac srcdir="" 
    destdir=""
    executable="path-to-java14-home/bin/javac" 
    fork="true"
    taskname="javac1.4" />

Considerações finais

Especificar uma versão do Java é uma boa prática para evitar problemas inesperados durante a entrega de um software. Procure compilar e testar seus programas usando a mesma versão do ambiente onde eles serão executados.

Este artigo descreve várias formas de atingir isso, para você ter um ambiente de desenvolvimento “saudável”.

Por este e outros motivos, recomendo o uso do Maven para novos projetos, já que ele evita a repetição do processo de configuração do ambiente para cada novo desenvolvedor ou servidor.

Para maiores detalhes sobre o Maven, consulte o artigo: Instalando, configurando e usando o Maven para gerenciar suas dependências e seus projetos Java.

Instalando, configurando e usando o Maven para gerenciar suas dependências e seus projetos Java

Este artigo é uma introdução ao Maven, uma ferramenta de gerenciamento de dependências e ciclo de vida de um projeto em Java.

Para usar o Maven, você precisa ter o JDK instalado. Você também pode integrá-lo à sua IDE. Para saber como instalar o JDK e o Eclipse, consulte os seguintes artigos:

O que é o Maven?

O Maven é uma ferramenta de gerenciamento de dependências e do ciclo de vida de projetos de software no sentido técnico. Isso inclui:

  • Facilitar a compilação do código, o empacotamento (JAR, WAR, EAR, …), a execução de testes unitários, etc.
  • Unificar e automatizar o processo de geração do sistema. Nada mais de uma coleção de passos e scripts a serem executados manualmente.
  • Centralizar informações organizadas do projeto, incluindo suas dependências, resultados de testes, documentação, etc.
  • Reforçar boas práticas de desenvolvimento, tais como: separação de classes de teste das classes do sistema, uso de convenções de nomes e diretórios, etc.
  • Ajuda no controle das versões geradas (releases) dos seus projetos.

Conceitos importantes

Artefato (artifact)

Um artefato é geralmente um arquivo JAR que fica no repositório do Maven, mas pode ser de outro tipo.

Cada artefato é identificado através dos seguintes elementos:

  • Grupo: é como o endereço do site ao contrário, como br.com.starcode, org.apache, com.google, com.ibm, etc.
  • Identificador único de artefato: geralmente é o nome do projeto. Ele deve ser único por grupo.
  • Número de versão: a versão do projeto, como 1.4.2 ou 3.0. Se houver o sufixo -SNAPSHOT (0.0.1-SNAPSHOT, por exemplo) significa que o projeto está em desenvolvimento e o pacote pode ser alterado.
  • Tipo do projeto: jar, war, ear, pom (projeto de configuração).
  • Classificador: identificação opcional para diferenciar variações da mesma versão. Por exemplo, se o programa é compilado para diferentes versões do Java podemos usar os classificadores jdk4 e jdk6. Se há variações específicas para Sistemas Operacionais, podemos ter os classificadores linux e windows.

Repositório local

É um diretório em seu PC onde os artefatos são armazenados após baixados de um repositório remoto na internet ou na intranet. Você também pode instalar os artefatos dos seus projetos nesse repositório executando o install do Maven. Continue lendo para entender o que é isso.

O repositório possui uma estrutura padrão onde o Maven consegue encontrar os artefatos através da identificação do mesmo.

Repositório remoto

Consiste numa aplicação que disponibiliza artefatos do Maven. Pode se um repositório público na Internet, onde criadores de bibliotecas e frameworks disponibilizam seus artefatos, ou pode ser um repositório privado da empresa, disponível na intranet.

Existe um repositório central que já vem configurando no Maven, mas algumas empresas criam seus próprios repositórios. Inclusive você pode criar o seu instalando o Artifactory ou Nexus num servidor.

Quando adicionamos esses repositórios remotos em nossa instalação do Maven, ele é capaz de localizar e baixar automaticamente as dependências através da identificação do artefato.

Arquivo POM

O arquivo pom (pom.xml) é a configuração principal do Maven e estará presente em todo projeto. Nele você declara a identificação do seu projeto (que após gerado será também um artefato Maven), as dependências, repositórios adicionais, etc.

Há um arquivo pom por projeto, mas ele pode herdar configurações de um parent pom, isto é, como se houvesse um projeto "pai".

Ciclo de vida padrão do Maven

O Maven possui um ciclo de vida padrão. Cada passo do ciclo de vida é chamado de Goal e possui plugins específicos. Os mais importantes são:

  • validate: valida o projeto e se as informações necessárias para os próximos passos estão disponíveis, como as dependências por exemplo.
  • compile: compila o código-fonte.
  • test: executa os testes unitários (JUnit, por exemplo).
  • package: empacota o código compilado em um JAR, WAR, etc.
  • integration-test: executa os testes de integração.
  • install: adiciona o pacote gerado ao repositório local, assim outros projetos na mesma máquina podem usar essa dependência.
  • deploy: copia o pacote final para o repositório remoto, disponibilizando-o para outros desenvolvedores e outros projetos.

Os itens acima, nessa ordem, são passos comuns para geração de uma versão de qualquer sistema, não é mesmo?

No Maven, você pode configurar detalhadamente cada um desses passos e até incluir novos. Por exemplo, alguns frameworks que geram código-fonte usam um goal generate-sources para fazer isso.

Além disso, não é necessário executar todos os passos sempre. Você pode escolher qual deseja executar num determinado momento, mas o Maven sempre executará todos os passos anteriores.

Por exemplo, enquanto você está desenvolvendo um módulo, a cada alteração pode executar o passo test para executar a validação, compilação e então os testes unitários. Então você só precisa executar os passos posteriores quando tiver concluído o trabalho.

Para maiores informações sobre o ciclo de vida, consulte a documentação.

Estrutura padrão de um projeto Maven

A estrutura padrão do projeto inclui boas práticas (como separar as classes de teste das classes do sistema) e facilita aos novos desenvolvedores encontrar o que eles querem, já que todos os projetos seguirão uma estrutura semelhante.

Veja a seguir os principais diretórios utilizados:

  • src/main/java: aqui fica o código-fonte do sistema ou biblioteca.
  • src/main/resources: arquivos auxiliares do sistema, como .properties, XMLs e configurações.
  • src/main/webapp: se for uma aplicação web, os arquivos JSP, HTML, JavaScript CSS vão aqui, incuindo o web.xml.
  • src/test/java: as classes com seus testes unitários ficam aqui e são executadas automaticamente com JUnit e TestNG. Outros frameworks podem exigir configuração adicional.
  • src/test/resources: arquivos auxiliares usados nos testes. Você pode ter properties e configurações alternativas, por exemplo.
  • pom.xml: é o arquivo que concentra as informações do seu projeto.
  • target: é o diretório onde fica tudo que é gerado, isto é, onde vão parar os arquivos compilados, JARs, WARs, JavaDoc, etc.

Para ver mais detalhes sobre a estrutura de diretórios do Maven, consulte a documentação.

Usando o Maven em projetos já existentes

Você pode ter ficado desapontado com a estrutura anterior, pois estava pensando em usar o Maven em um projeto que já começou, mas não quer ou não pode mudar a estrutura de pastas atuais.

Saiba que o Maven é flexível e permite alterar toda a estrutura padrão.

Por exemplo, é comum usar a pasta src para os fontes, ao invés de src/main/java. Para ajustar isso, basta adicionar uma tag <sourceDirectory> dentro da tag <build>, assim:

<project>
    ...
    <build>
        <sourceDirectory>src</sourceDirectory>
        ...
    </build>
    ...
</project>

Não vou ir fundo nessa questão, mas se o leitor tiver um projeto em condições semelhantes, sugiro uma leitura mais completa da documentação, começando com Using Maven When You Can’t Use the Conventions.

É claro que nem tudo é tão simples. Muitos projetos usam estruturas tão diferentes que se exige a refatoração desta estrutura.

Benefícios do Maven

A adoção do Maven no desenvolvimento traz de imediato os seguintes benefícios:

Centralização das informações

O Maven centraliza as informações dos projetos no arquivo pom.

Sendo assim, não é preciso configurar várias ferramentas, build scripts, servidores e IDEs durante o desenvolvimento. O Maven segue o conceito DRY (Don’t Repeat Yourself).

Além disso, o Maven também disponibiliza formas de analisar o projeto. Por exemplo, o goal dependency:analyze exibe as dependências declaradas que não estão sendo usadas e as usadas via terceiros, mas não declaradas no pom.

Padronização do ambiente de desenvolvimento

Através da especificação do projeto, incluindo suas características e dependências, o Maven constrói a estrutura necessária do projeto, baixando automaticamente as versões corretas das dependências (JARs, por exemplo) de um repositório central ou de um repositório privado (contendo sistemas da empresa).

Você não precisa entrar no site de cada biblioteca e framework usado e então fazer manualmente o download e adicionar os jars no seu classpath.

Dessa forma, cada desenvolvedor consegue configurar rapidamente um ambiente para desenvolvimento com a garantia de que esse ambiente é igual ao dos outros desenvolvedores.

Gerenciamento de dependências

Como já mencionei, o Maven faz o download automático de dependências para o projeto e os adiciona ao classpath do seu projeto.

Cada dependência pode ter também as suas próprias dependências. Elas são chamadas dependências transitivas. O Maven resolve essa árvore de dependências e traz tudo o que você precisa.

Em alguns casos, podem haver problemas de conflitos, no caso da árvore de dependências incluir versões diferentes de um mesmo artefato. O Maven vem com mecanismos para resolver isso.

Facilidade de compreensão do projeto

Ao usar a convenção de diretórios sugerida pelo Maven os desenvolvedores terão mais facilidade em compreender a estrutura do projeto, afinal todos os projetos seguirão uma estrutura básica de diretórios, como vimos anteriormente.

Automação

O Maven gerencia o ciclo de vida da aplicação. Após configurar um projeto, você será capaz de executar comandos que vão desde a compilação até a geração de documentação (Javadoc) e um site padrão contendo informações sobre o projeto.

Uma vez feita a configuração necessária, o projeto pode ser baixado e compilado sem nenhum esforço. Novas versões podem ser geradas em servidores de Integração Contínua e testadas automaticamente sempre que necessário.

Um alerta

Embora os tópicos anteriores tenham enumerado diversas vantagens do uso do Maven, este não é uma "bala de prata", ou seja, uma solução mágica para o projeto.

Dependendo da complexidade do projeto, pode ser bem complicado criar uma configuração adequada para ao Maven.

Além disso, o Maven não irá livrá-lo de problemas como:

Incompatibilidade de dependências

O projeto depende dos frameworks A e B. O framework A depende a versão 1.0 da biblioteca C. O framework B depende da versão 2.0 da biblioteca C.

O Maven não vai resolver sozinho isso, mas facilita muito a resolução do problema já que podemos usar as informações do mecanismo de resolução de dependências para identificar os conflitos.

Algumas tecnologias simplesmente não vão funcionar bem com o Maven

Alguns autores de frameworks ou arquiteturas inventam o seu próprio jeito de trabalhar. Isso significa que para usar o Maven é necessário alguma adaptação, o que nem sempre é trivial.

No entanto, é possível escrever plugins para o Maven que façam o trabalho para você. Geralmente a comunidade de cada framework, se não os próprios autores, já terão resolvido esse problema. Embora existam casos em que essas soluções acrescentem novas limitações.

Ódio do Maven

A verdade é que existe muita gente que odeia o Maven por ter vivido experiências ruins com ele, principalmente no início. Infelizmente, não sei se este artigo terá o poder de curá-lo de traumas passados ao tentar usar o Maven sem a devida orientação. 😉

No entanto, não deixe que isso influencie você neste momento. Mesmo que não pretenda usar o Maven em seus projetos, vale a pena conhecê-lo. Você pode ser obrigado a usá-lo na empresa ou mesmo num projeto opensource de que vai participar.

Se você não gosta do Maven, tenha duas coisas em mente:

  1. Existem várias alternativas, desde scripts Ant até outras ferramentas de resolução de dependências mais avançadas como o Graddle.
  2. Embora algumas pessoas atinjam um excelente nível de produtividade sem o Maven, se considerarmos um contexto mais amplo, como um projeto que com mais de meia dúzia de desenvolvedores, alguns deles novatos, o Maven pode trazer mais vantagens que desvantagens se bem configurado por um desenvolvedor experiente.

Instalando o Maven

Acesse a página do Maven e clique no item Download do menu.

A página disponibiliza diferentes versões para diferentes ambientes. Baixe o arquivo da última versão de acordo com seu sistema operacional. Destaquei na imagem a versão zip para Windows que usarei neste exemplo:

01

A versão mais atual do Maven na data de criação deste tutorial é 3.2.1. O pacote baixado é nomeado apache-maven-3.2.1-bin.zip. Veja o arquivo aberto no 7-Zip:

02

Descompacte o conteúdo para a pasta c:\starcode\.

03

Configura o resultado na imagem a seguir:

04

Configurando o Maven

O Maven é configurado através do arquivo settings.xml que fica no diretório c:\starcode\apache-maven-3.2.1\conf.

Abra o arquivo usando um editor avançado, como o Notepad++. Você vai ver que existem diversos blocos de XML comentados com possíveis configurações e explicações sobre elas.

Em um ambiente simples você não vai precisar mexer em muita coisa. Porém, vamos ver alguns pontos mais importantes.

Proxy

É muito comum precisarmos autenticar o acesso à internet em um Proxy quando estamos no trabalho. Procure a tag <proxy>, a qual deve estar comentada no arquivo de configuração. O trecho é o seguinte:

<proxy>
    <id>optional</id>
    <active>true</active>
    <protocol>http</protocol>
    <username>proxyuser</username>
    <password>proxypass</password>
    <host>proxy.host.net</host>
    <port>80</port>
    <nonProxyHosts>local.net|some.host.com</nonProxyHosts>
</proxy>

Se você tem um proxy na sua rede, mova o bloco acima para fora do comentário, então substitua os parâmetros de acordo com seu ambiente. Mantenha a tag <proxy> dentro de <proxies>.

Veja abaixo um exemplo de uso:

<proxies>
    <proxy>
        <id>proxy</id>
        <active>true</active>
        <protocol>http</protocol>
        <host>proxy.intranet.empresa.com</host>
        <port>8080</port>
        <nonProxyHosts>localhost,127.*,192.*</nonProxyHosts>
    </proxy>
</proxies>

Local do repositório

O Maven utiliza um diretório local para baixar os artefatos da internet. O diretório padrão fica dentro pasta do usuário, na pasta .m2. Um exemplo no Windows é c:\users\luiz\.m2\repository.

Entretanto, tenho o hábito de mudar esse diretório para junto de meus arquivos de desenvolvimento. Para isso, basta editar o settings.xml, movendo a tag <localRepository> para fora do comentário e adicionando o caminho, por exemplo:

<localRepository>c:\starcode\apache-maven-3.2.1\repo</localRepository>

Não se esqueça de criar o diretório especificado caso o mesmo não exista.

Configurando as variáveis de ambiente

Para usar o Maven em linha de comando você deve adicionar o caminho para os executáveis ao PATH do ambiente. No Windows, pressione Ctrl+Break para abrir a tela de informações do do sistema.

05-configurar-maven

Clique na opção Configurações avançadas do sistema, à esquerda da janela.

06-configurar-maven

Na aba Avançado da tela de Propriedades do Sistema, clique em Variáveis de Ambiente....

07-configurar-maven

Você pode adicionar a variável de ambiente apenas para o usuário atual ou globalmente para todo o sistema. Faça o que for melhor para o seu caso. Alguns ambientes corporativos impedem o acesso à configuração de sistema por questões de segurança, então você terá que configurar apenas seu usuário.

Clique em Novo... e crie a variável M2_HOME com o valor apontando para o diretório base do Maven. No nosso exemplo o valor é c:\starcode\apache-maven-3.2.1.

08-configurar-maven

Clique em OK para criar a variável.

09-configurar-maven

Agora vamos incluir o diretório com os executáveis do Maven ao PATH. Localize a entrada, selecione-a e clique em Editar....

10-configurar-maven

Adicione ao final um ponto e vírgula e o caminho para a pasta bin do Maven (;%M2_HOME%\bin), assim:

11-configurar-maven

Clique em OK para confirmar a edição e OK novamente para confirmar as alterações nas variáveis do sistema.

Vamos então testar a instalação. Abra o CMD (linha de comando) e digite mvn -version. Você deve ver algo como na figura abaixo:

12-configurar-maven

Se ocorreu algum problema, verifique se você tem o Java instalado e configurado corretamente, incluindo as variáveis de ambiente JAVA_HOME e PATH incluindo o Java. Caso tenha dúvidas, acesse o artigo citado no início sobre a instalação do JDK.

Usando o Maven

Usando a instalação do Maven no Eclipse

Para integrar o Maven e Eclipse eu aconselho o plugin M2E. Note que o M2E é um plugin do Eclipse que faz integração com o Maven.

Existe também o Maven Eclipse Plugin, aquele onde se digita eclipse:eclipse para gerar um projeto para o Eclipse. Este é um plugin do Maven que simplesmente gera os arquivos de configuração necessários para a IDE. Não confunda os dois.

A distribuição Eclipse for JEE Developers já vem com o plugin M2E e uma instalação interna do Maven. Veja como instalar e usar o Eclipse acessando o artigo citado no início.

Se você tem uma versão diferente do Eclipse, use o menu Help > Eclipse Marketplace..., pesquise por M2E e instale o plugin.

Com o plugin instalado e o Eclipse aberto, acesse o menu Window > Preferences... e vá até a opção Maven > Installations.

01-maven-eclipse

Veja que já existe uma instalação "embarcada", mas com uma versão desatualizada. Vamos adicionar o nosso Maven.

Clique em Add... e selecione a pasta com a nossa instalação, no caso: c:\starcode\apache-maven-3.2.1.

02-maven-eclipse

Note que ele já encontrou nosso arquivo de configuração.

Vá até o menu User Settings. Há um warning lá dizendo que a configuração do usuário não existe. Você pode criar um outro settings.xml na pasta indicada ou simplesmente use um artifício (que eu sempre uso), que é definir o mesmo arquivo da configuração global.

03-maven-eclipse

Caso não tenha entendido, o Maven possui um arquivo de configuração global que afeta diretamente a instalação e fica na pasta conf. Entretanto, cada usuário do sistema pode ter um arquivo próprio e sobrescrever as configurações globais que ele desejar. No entanto, se você é o único usuário do computador, não é necessário ter os dois arquivos.

Criando um projeto Maven simples no Eclipse

Com o Maven configurado, vamos criar um novo projeto no Eclipse. Acesse o menu File > New > Maven Project. Selecione a opção Create a simple project (skip archetype selection) e clique clique em Next >.

01-projeto-simples

Vamos preencher a identificação do projeto, que nada mais é do que a identificação de um artefato.

02-projeto-simples

O Group Id para o exemplo será br.com.starcode e o Artifact Id será teste-maven-01. A versão e o tipo de artefato (Packaging) já devem estar preenchidos, então simplesmente deixe como está. O nome e a descrição são opcionais.

Clique em Finish para ver o projeto criado.

Note que ele ainda não está definido com as configurações de um projeto Java, então clique com o botão direito sobre o projeto, acesse o menu Maven > Update Project....

03-projeto-simples

Clique em OK para atualizar o projeto com as configurações do Maven e agora temos a estrutura característica.

04-projeto-simples

Adicionando manualmente uma dependência

Agora vou ilustrar como podemos adicionar algumas dependências ao projeto. Acesse o site mvnrepository.com, que contém um índice das dependências disponíveis no repositório do Maven. Pesquise por commons-lang.

05-projeto-simples

Selecione o item Apache Commons Lang, como indicado na imagem abaixo:

06-projeto-simples

Clique sobre a última versão (3.3.2 na data em que escrevo o artigo).

07-projeto-simples

Selecione e copie a identificação do artefato, conforme a imagem abaixo:

08-projeto-simples

Agora volte ao Eclipse e clique duas vezes sobre o arquivo pom.xml para editá-lo. Provavelmente o editor foi aberto no aba Overview (veja abaixo do editor) com diversos campos e informações sobre o projeto.

Clique na aba pom.xml para mostrar o código fonte.

09-projeto-simples

Adicione a tag <dependencies> logo abaixo da tag <description> e cole o conteúdo do site dentro dela.

Dica: Pressione CTRL+A para selecionar todo o conteúdo do arquivo e depois CTRL+I para indentar (tabular) o arquivo.

10-projeto-simples

O conteúdo do pom.xml deve ser o seguinte:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>br.com.starcode</groupId>
    <artifactId>teste-maven-01</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>Teste Maven 01</name>
    <description>Um teste de projeto simples com o maven</description>
    <dependencies>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.3.2</version>
        </dependency>
    </dependencies>
</project>

Salve o arquivo. O plugin M2E irá identificar a alteração, baixar automaticamente a dependência do repositório central para o seu repositório local e adicioná-la ao classpath do projeto.

Confira a entrada Maven Dependencies na imagem a seguir:

11-projeto-simples

Pronto! Agora você já pode usar qualquer classe da biblioteca Apache Commons Lang. 😉

Fiz uma classe de exemplo (File > New > Other..., selecione Class), com o seguinte conteúdo:

package br.com.starcode.testemaven01;

import org.apache.commons.lang3.StringUtils;

public class ClasseDeTeste {

    public static void main(String[] args) {

        System.out.println(StringUtils.capitalize("luiz"));

    }

}

Executei o método main clicando com o botão direito sobre a classe, menu Run As > Java Application. Veja o resultado:

12-projeto-simples

Executando os passos (goals) do Maven

Vamos supor que estamos construindo uma nova biblioteca. Precisaremos testá-la (test), empacotá-la (package) num jar e distribuí-la (deploy) para o uso de terceiros, não é mesmo? O Maven nos ajuda grandemente com esses passos naturais do ciclo de vida de um projeto.

Vamos usar nosso projeto de exemplo e criar uma classe utilitária chamada SuperUtil:

package br.com.starcode.testemaven01;

import org.apache.commons.lang3.StringEscapeUtils;

public class SuperUtil {

    /**
     * Possibilita exibir um texto contendo HTML no navegador sem ataques XSS.
     * @param html Entrada do usuário (pode ter HTML, mas não deve ser renderizado, somente exibido)
     * @return Texto sem posíveis tags HTML
     */
    public static String escapeHTML(String html) {
        return StringEscapeUtils.escapeHtml4(html);
    }

}

Veja no Eclipse:

01-executando-com-maven

Vamos ainda criar um teste unitário para nossa classe, as primeiro temos que adicionar a dependência do JUnit ao nosso projeto. Para isso vá até o site mvnrepository.com e pesquise por junit. Vá até a última versão, copie o trecho do XML e adicione na seção de dependências do seu pom.xml.

Adicione também a tag <scope>test</scope> à esta dependência, para informar ao Maven que ela somente será usada no teste. Sim, o Maven é “esperto” e não incluirá, por exemplo, o JUnit na pasta WEB-INF/lib de uma aplicação web.

Veja como ficou o pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>br.com.starcode</groupId>
    <artifactId>teste-maven-01</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>Teste Maven 01</name>
    <description>Um teste de projeto simples com o maven</description>
    <dependencies>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.3.2</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

Ao salvar o arquivo o Maven deve baixar o JUnit automaticamente.

Agora crie a classe de teste SuperUtilTest em src/test/java:

package br.com.starcode.testemaven01;

import org.junit.Assert;
import org.junit.Test;

public class SuperUtilTest {

    @Test
    public void escapeHTMLTest() {

        String escapedHtml = SuperUtil.escapeHTML("<script>alert(1);</script>");
        String expected = "&lt;script&gt;alert(1);&lt;/script&gt;"; 
        Assert.assertEquals(expected, escapedHtml);

    }

}

Caso queira executar o teste já, clique com o botão direito sobre a classe e acesse o menu Run As > JUnit Test:

02-executando-com-maven

Confira o resultado:

03-executando-com-maven

Sucesso! 😀

Imagine agora que tenhamos criado diversas classes e métodos. Temos uma versão beta de nossa biblioteca.

Vamos testar o projeto usando o Maven. Clique no projeto com o botão direito e na opção Run As > Maven test:

04-executando-com-maven

Na primeira execução o Maven vai baixar diversos plugins e dependências internas para a execução do projeto. Aguarde um pouco e confira o resultado de todos os testes do projeto:

05-executando-com-maven

Ok, agora vamos gerar um JAR do projeto. Clique no projeto com o botão direito e na opção Run As > Maven build.... Isso é necessário porque não é uma opção pronta para o passo package. Vá até o campo Goals e digite package.

06-executando-com-maven

Clique em Run e aguarde.

07-executando-com-maven

Se você observar o log no Console notará que os testes foram executados. Lembra que eu disse que os passos anteriores sempre são executados? Espero que agora tenha entendido melhor.

Note a última linha antes das palavras BUILD SUCCESS. Ali está o caminho do Jar gerado. Ele foi gerado dentro da pasta target do projeto.

Selecione a pasta target e Pressione F5 para atualizá-la. Abra-a clicando na seta à esquerda e confira:

08-executando-com-maven

Vamos agora executar o install, isto é, instalar o jar no repositório local. Clique no projeto com o botão direito e na opção Run As > Maven install. Aguarde um pouco e veja o resultado:

09-executando-com-maven

As duas últimas linhas antes da mensagem de sucesso demonstram os locais onde o Jar e o seu arquivo POM foram instalados:

[INFO] Installing D:\starcode\workspaces\workspace_demo\teste-maven-01\target\teste-maven-01-0.0.1-SNAPSHOT.jar to c:\starcode\apache-maven-3.2.1\repo\br\com\starcode\teste-maven-01\0.0.1-SNAPSHOT\teste-maven-01-0.0.1-SNAPSHOT.jar

[INFO] Installing D:\starcode\workspaces\workspace_demo\teste-maven-01\pom.xml to c:\starcode\apache-maven-3.2.1\repo\br\com\starcode\teste-maven-01\0.0.1-SNAPSHOT\teste-maven-01-0.0.1-SNAPSHOT.pom

Vamos abrir o diretório do repositório local e dar uma olhadinha:

10-executando-com-maven

Agora você pode usar este artefato em outros projetos na sua máquina local, adicionando a seguinte dependência:

<dependency>
    <groupId>br.com.starcode</groupId>
    <artifactId>teste-maven-01</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

Qualquer projeto com essa dependência vai usar o nosso jar gerado e, automaticamente, incluir também o jar do Apache Commons Lang que definimos em nosso projeto.

Analisando as dependências

Vamos aprender a analisar as dependências de um projeto.

Abra novamente o seu arquivo pom.xml e vá até a aba Dependency Hierarchy. Você deve estar vendo isso:

01-maven-dependencies

Abaixo, mais um exemplo de dependências extraído da minha biblioteca T-Rex:

maven-dependency-hierarchy

Usando o Maven em linha de comando

Tudo o que fizemos anteriormente através da IDE pode ser feito via linha de comando. É importante entender isso porque quando o projeto for compilado em um servidor de Integração Contínua, por exemplo, ele não contará com as facilidades do plugin que usamos.

Irei ilustrar a seguir a execução do goal install via linha de comando.

O primeiro passo é abrir o CMD e ir até o diretório do projeto. Então basta digitar o comando maven install.

11-executando-com-maven

Configura o resultado da execução:

13-executando-com-maven

Pronto!

Explicando: nós adicionamos o Maven ao path do sistema, lembra? maven é o nome do executável do Maven e install é o goal que você deseja executar. Também há usar o executável mvn, que é apenas um atalho para evitar digitar mais caracteres.

Da mesma forma, poderíamos executar mvn test ou mvn package como fizemos nos tópicos acima via menu do Eclipse para ativar os respectivos Goals.

Um goal muito importante ainda não mencionado é o clean, que serve para limpar todos os arquivos gerados da pasta target. Ele é muito importante para limpar eventual “sujeira” de gerações anteriores.

Quando estiver tendo problemas estranhos ou for gerar uma versão "oficial", sempre use comandos comandos como mvn clean install ou mvn clean deploy para garantir uma geração "limpa".

Note que você pode especificar vários goals simultaneamente para o Maven executar. Nos exemplos acima, o Maven vai primeiro limpar o projeto e depois executar o install ou o deploy.

Passando parâmetros para o Maven

Há ainda situações onde precisamos ajustar a execução do Maven através de parâmetros.

Por exemplo, em certas ocasiões queremos gerar um jar ou war para testes, porém o build do Maven falha porque um teste unitário terminou em erro.

Para resolver essa situação sem excluir o teste unitário, é possível configurar o Maven para “pular” os testes com o seguinte comando:

mvn -DskipTests clean install

14-executando-com-maven

Configura o resultado da execução:

15-executando-com-maven

O mesmo resultado pode ser obtido no Eclipse clicando com o botão direito sobre o projeto e indo no menu Run As > Maven build..., digitando clean install no campo Goals e selecionando a opção Skip Tests.

Distribuindo seu projeto

Os próximos passos incluiriam disponibilizar o jar para outros desenvolvedores através do goal deploy. Em um deploy, o Maven envia seu jar para um Repositório Remoto. Entretanto, isso exige várias configurações adicionais e as devidas permissões.

Disponibilizar seu projeto no repositório central do Maven exige que seu projeto seja opensource e que você solicite as permissões necessárias. Caso você queira fazer isso, siga os passos disponíveis neste link.

Já dentro de uma empresa geralmente se configura um servidor para conter um repositório com os artefatos da empresa. Existem aplicações gratuitas que podem ser usadas para isso, como o Artifactory ou o Nexus.

As configurações necessárias para o deploy num repositório remoto estão fora do escopo deste artigo, mas existem várias referências disponíveis na web.

Leitura adicional

Usar o Maven para desenvolver projetos pessoais é relativamente fácil e este artigo cobre o necessário para isso. Entretanto, não deixe de estudar o material oficial e, aos poucos, ir entendendo os mecanismos do Maven para usá-lo em projetos maiores:

Considerações finais

Usar o Maven pode ser confuso a princípio, mas traz diversos benefícios.

Em curto prazo ele ajuda você a gerenciar as dependências e organizar seus projetos.

Em médio prazo você poderá ter um controle muito bom de versões e releases, além de um padrão maduro para seus projetos.

Em longo prazo o Maven possibilitará a Integração Contínua de seus projetos. Será necessário um esforço considerável, mas seus projetos serão compilados e testados automaticamente. Com uma quantidade de testes adequada para garantir que as funcionalidades existentes continuam funcionando e as novas vão funcionar, você pode ter versões sendo geradas todos os dias ou a cada commit!

Nesse ponto, cruzamos com conceitos de TDD, Agile e outros. Mas é exatamente este o motivo pelo qual ferramentas de automação como o Maven são importantes.

Espero que o leitor tenha compreendido seu funcionamento básico e possa evoluir daqui em diante para um melhor aproveitamento da automação em benefício da qualidade e da agilidade.

Instalando e configurando o Eclipse Kepler no linux Ubuntu

Continuando a série de artigos sobre configuração de um ambiente de desenvolvimento no linux Ubuntu em uma máquina virtual, chegou a hora do Eclipse.

Você deve ter o JDK instalado no seu Ubuntu. Os passos de instalação do Ubuntu e do Java estão em seus respectivos artigos:

Baixando o Eclipse

Acesse a página de download do Eclipse a partir do seu Ubuntu. Vamos fazer o download da versão Eclipse IDE for Java EE Developers, que já vem com um conjunto maior de plugins do que a versão Standard.

Meu Ubuntu é de 64 bits, portanto vou selecionar a opção Linux 64 Bit, conforme indicado na imagem:

install-eclipse-01

Na próxima tela, clique na seta verde para iniciar o download.

install-eclipse-02

Salve o arquivo no local desejado e aguarde o término do download.

install-eclipse-03

Instalando o Eclipse

Ainda no navegador, clique sobre o nome do arquivo para abri-lo, conforme a imagem abaixo. Ou simplesmente abra o gerenciador de arquivos e navegue até o diretório onde baixou o arquivo e abra-o com um duplo clique. O arquivo deve ter sido baixado no diretório ~/Downloads, que é a pasta padrão de downloads do usuário.

install-eclipse-04

Agora, o arquivo deve estar aberto no Archive Manager, conforme a imagem:

install-eclipse-05

Selecione a pasta eclipse que aparece na listagem do programa e clique no botão Extract da barra de ferramentas.

A caixa de diálogo de extração aparecerá. Navegue até um diretório de sua preferência para descompactar o Eclipse. Se estiver em dúvida ou tiver problemas de permissão, use o diretório Home (~), como na imagem.

install-eclipse-06

Clique no botão Extract para confirmar a extração.

Após a conclusão, o Archive Manager mostratá um diálogo. Clique em Show the Files para abrir o diretório Home. Acesse a pasta eclipse com um clique duplo.

install-eclipse-07

Você deve estar vendo os arquivos do Eclipse, incluindo o executável dele.

Ao invés de abri-lo, vamos criar um atalho para facilitar nas demais utilizações. Clique com o botão direito sobre o executável e selecione a opção Make Link.

install-eclipse-08

Um atalho deve ter sido criado como na imagem abaixo:

install-eclipse-09

Com o atalho selecionado, pressione CTRL+X para recortá-lo.

Minimize todas as janelas, clique com o botão direito no fundo da sua Área de Trabalho e selecione a opção Paste.

install-eclipse-10

Pronto!

Configurando o Eclipse

Antes de iniciar o Eclipse, vamos ajustar alguns parâmetro de memória para melhorar o desempenho geral de nossa IDE.

Primeiro, abra o explorador de arquivos e vá até o diretório onde extraiu os arquivos do Eclipse. No nosso caso é ~/eclipse.

install-eclipse-15

Clique com o botão direito sobre o arquivo eclipse.ini e abra com um editor de texto. Você verá o arquivo com o conteúdo a seguir:

install-eclipse-16

Vamos aumentar um pouco os parâmetros de memória:

install-eclipse-17

O conteúdo do arquivo ficou assim:

-startup
plugins/org.eclipse.equinox.launcher_1.3.0.v20130327-1440.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.1.200.v20140116-2212
-product
org.eclipse.epp.package.jee.product
--launcher.defaultAction
openFile
-showsplash
org.eclipse.platform
--launcher.XXMaxPermSize
256m
--launcher.defaultAction
openFile
--launcher.appendVmargs
-vmargs
-Dosgi.requiredJavaVersion=1.6
-XX:MaxPermSize=256m
-Xms512m
-Xmx1G

Feche o editor e não esqueça de salvar o arquivo.

Executando o Eclipse

Clique duas vezes sobre o ícone que criamos na área de trabalho. A splash screen irá aparecer.

install-eclipse-11

Aguarde e logo você será saudado pelo Workspace Launcher para selecionar o Workspace de trabalho.

install-eclipse-12

Clique em OK para criar um novo Workspace no diretório indicado. Aguarde mais um pouco para ver a tela de boas-vindas.

install-eclipse-13

Clique no link Workbench para fechar a tela de abertura e ir à perspectiva de desenvolvimento.

install-eclipse-14

Agora é só usar!

Usando o Eclipse

Caso não esteja acostumado com o Eclipse, não deixe de ler o artigo Instalando, Configurando e Usando o Eclipse Kepler.

Embora o tutorial seja para instalação no Windows, na segunda parte você encontra detalhes sobre como realizar configurações básicas, criar um projeto, executar e depurar um programa, além de informações sobre os componentes principais do Eclipse.

Considerações finais

Com Java e o Eclipse instalados no linux, você já tem um ambiente para iniciar o desenvolvimento de aplicações.

Pretendo em artigos futuros usar este ambiente para ilustrar o desenvolvimento de aplicações Big Data com Hadoop.

Instalando e configurando o JDK 7 no linux Ubuntu

Neste pequeno tutorial você aprenderá a instalar o Java Development Kit 7 no linux Ubuntu. O JDK consiste no conjunto de ferramentas para desenvolvimento em Java.

Caso você não tenha acompanhado, publiquei recentemente em um tutorial sobre como instalar o Ubuntu numa máquina virtual. Esta é uma espécie de continuação da série de artigos que visa a configuração de um ambiente de desenvolvimento no Linux. Com esse ambiente, poderemos brincar livremente bom Big Data. Não perca este e os próximos capítulos! 😉

Instalando o JDK 7

Antes de mais nada vamos verificar se, por acaso, já não temos o JDK instalado. Abra o terminal e digite:

javac

install-jdk-02

Note a mensagem de que o programa não foi encontrado. O próprio Ubuntu nos dá uma dica do comando de instalação. Vamos aceitar a sugestão e instalar o pacote openjdk_7-jdk. Digite o comando:

sudo apt-get install openjdk-7-jdk

O terminal irá solicitar a senha. Digite-a.

install-jdk-03

Depois ele vai pedir a confirmação da operação.

install-jdk-04

Pressione Y para aceitar e aguarde o download e a instalação do pacote.

install-jdk-05

Vamos digitar novamente o comando javac para verificar a instalação.

install-jdk-06

Pronto!

Onde está o Java?

Vamos agora conferir onde o Java foi realmente instalado. Para isso, no terminal, digite o comando abaixo para navegar até o diretório onde geralmente ficam as instalações do Java:

cd /usr/lib/jvm

Agora vamos listar os arquivos no diretório com o comando ls:

install-jdk-08

Em nosso exemplo temos duas entradas: java-1.7.0-openjdk-amd64 e java-7-openjdk-amd64.

Ué!? Mas não instalamos apenas uma versão do Java? Sim! Note que cada entrada tem uma cor diferente. O azul mais claro do primerio item indica que ele é um link simbólico (symbolic link), isto é, um simples um atalho. Vamos confirmar com o comando abaixo:

ln -li

install-jdk-09

Notou a seta que demonstra o link apontando para a pasta original?

Enfim, o Java foi instalado no diretório /usr/lib/jvm/java-7-openjdk-amd64, como podemos ver na imagem a seguir:

install-jdk-10

Algumas configurações adicionais

Embora o Java já funcione apenas com a instalação realizada, vamos configurar as variáveis de ambiente para o caso de algum programa procurar o JAVA_HOME.

Vamos novamente verificar se, por acaso, esta variável já existe usando o comando abaixo:

echo $JAVA_HOME

install-jdk-07

Nada. Então vamos defini-la em nossa sessão com o seguinte comando:

JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64

Em seguida, vamos exportar a variável para os demais programas com o comando export:

export JAVA_HOME

Somente como observação, poderíamos ter feito os dois passos anteriores em apenas um comando da seguinte forma:

export JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64

Agora vamos testar se a variável está correta:

echo $JAVA_HOME

install-jdk-11

Tudo certo até agora!

O problema é que o comando export não salva a variável de forma permanente, ou seja, se reiniciarmos o computador (ou máquina virtual), perderemos seu valor. A fim de persisti-la e disponibilizá-la para todos os usuários, vamos criar um script que faz a exportação da variável durante a inicialização do ambiente e a torna disponível para todos os usuários do sistema.

Isso é feito com um Shell script no diretório /etc/profile.d. Todos os scripts neste diretório são executados na inicialização.

Primeiro, vamos até o diretório mencionado:

cd /etc/profile.d

install-jdk-12

Para não complicar muito, vamos usar o editor nano para criar um arquivo com permissão de administrador, então execute o seguinte comando:

sudo nano export_vars.sh

No editor, digite a linha abaixo:

export JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64

install-jdk-13

Em seguida, pressione CTRL+X para sair do programa (Exit). Ele vai perguntar se você quer salvar o conteúdo. Pressione Y e depois Enter.

Pronto de novo!

O arquivo export_vars.sh foi criado com sucesso. Podemos conferir o conteúdo com o comando cat, da seguinte forma:

cat export_vars.sh

install-jdk-14

Para mais detalhes sobre variáveis de ambiente veja a documentação do Ubuntu.

Considerações finais

Este tutorial tem a intenção de prepará-lo para tópicos mais avançados.

Entretanto, procurei ser detalhado nos comandos utilizados também para que o leitor possa se ambientar no ambiente linux, ao invés de apenas digitar comandos “às cegas” sem compreender o que está fazendo.

Apache POI: adicionando segurança em arquivos Excel

poi-original
A biblioteca Apache POI possibilita a leitura e gravação de documentos do Microsoft Office via código Java.

Por esses dias, fiz uma pesquisa sobre como essa biblioteca viabiliza (ou não) trabalharmos com arquivos protegidos do Excel.

Níveis de segurança do Office

Documentos do Excel podem ter diferentes níveis de proteção, a saber:

  • Proteção contra alteração: permite abrir o documento em modo somente-leitura, mas não deixa o usuário alterá-lo sem antes digitar a senha.
  • Proteção contra alteração de um trecho do documento: protege planilhas e células específicas com senha.
  • Proteção contra leitura: não permite abrir o documento sem a senha.

Todos esses modos podem ser usados ao mesmo tempo, inclusive com senhas diferentes.

Se o arquivo tiver proteção contra leitura, o Excel irá solicitar a senha antes de abrir o mesmo. Se houver proteção contra alteração ele irá solicitar a senha para desbloqueio da edição ou permitir acesso somente-leitura ao documento. Se planilhas ou células estiverem protegidas contra alteração, então o usuário deve acessar a função “Desproteger” no Excel e digitar a senha de desbloqueio para cada trecho.

As proteções contra alteração são simples travas no editor, pois o arquivo em si permanece aberto e não há restrições de alteração via programação ou com o uso de editores de terceiros. Podemos dizer que este mecanismo oferece um baixíssimo grau de segurança, que impedirá apenas o usuário mais leigo de efetivamente modificar o documento.

Por outro lado, a proteção contra leitura oferece um grau de segurança maior, pois o documento como um todo é criptografado. Isso significa que nenhum programa ou editor conseguirá sequer ler o documento sem antes descriptografar os bytes do arquivo com a senha original.

Versões dos documentos do Office

Quem acompanha o Office há algum tempo deve ter notado que, a partir da versão 2007, os documentos ganharam novas extensões, com o sufixo x. Por exemplo, doc passou a ser docx, xls mudou para xlsx e assim por diante.

Mas não foi apenas a extensão que mudou. O conteúdo foi completamente reformulado. O formato mais antigo era do tipo binário, enquanto os novos são baseados em XML.

As vantagens do formato XML são inúmeras, a começar pela capacidade de qualquer ferramenta que trabalha com XML conseguir processar o documento ou pelo menos parte dele.

No que se refere à biblioteca Apache POI, isso também nos afeta diretamente, pois há APIs diferentes para trabalhar com os diferentes formatos de documentos.

Como veremos adiante, nem todos os formatos suportam todos os tipos de segurança.

Capacidades do POI

A conclusão dos meus testes foi a seguinte:

Tipo de documento Operação Proteção contra alteração do documento Proteção contra alteração de uma planilha Proteção contra Leitura (criptografia)
XLS
Leitura OK
Criação N/D* OK N/D
XLSX
Leitura OK
Criação N/D OK OK

Na leitura de um arquivo XLS ou XLSX, as proteções contra alteração são ignoradas, então não há o que testar.
N/D = Não disponível, isto é, não há suporte na API.
* Existe um método para proteger o documento, mas ele não surte efeito (bug).

Como pode ser visto, para documentos no formato legado XLS o POI suporta apenas a leitura de arquivos criptografados. Na criação, ele apenas consegue proteger parte do documento contra alteração.

Já para o formato mais novo XLSX, o POI consegue ler e criar arquivos criptografados. Entretanto, na criação do documento, não há um método para proteger o documento todo contra alteração.

Alguns fóruns sugerem uma possibilidade de contornar a falta do recurso de proteger o documento como um todo contra alteração. Para isso, basta criar um arquivo Excel com tal proteção e usá-lo como template para geração de um novo.

Implementação

Criptografia em arquivos XLS

O POI suporta apenas ler arquivos criptografados neste formato, isto é, que estão protegidos contra leitura.

O segredo é a classe Biff8EncryptionKey. Basta definir a senha através do método estático setCurrentUserPassword e depois ler o arquivo normalmente.

Exemplo:

try {
    Biff8EncryptionKey.setCurrentUserPassword(password);
    new HSSFWorkbook(input);
} finally {
    Biff8EncryptionKey.setCurrentUserPassword(null);
}

É bom não esquecer de remover a senha ao final para não atrapalhar futuras leituras.

Mesmo sendo um método estático, não deve haver problemas de concorrências, pois a documentação afirma que a senha é armazenada usando ThreadLocal.

Criptografia em arquivos XLSX

O POI implementa tanto a leitura quanto a criação de documentos criptografados neste formato.

Veja minha implementação para a leitura:

public class XlsxDecryptor {

    public static XSSFWorkbook decrypt(InputStream input, String password)
            throws IOException {

        POIFSFileSystem filesystem = new POIFSFileSystem(input);
        EncryptionInfo info = new EncryptionInfo(filesystem);
        Decryptor d = Decryptor.getInstance(info);

        try {
            if (!d.verifyPassword(password)) {
                throw new RuntimeException("Unable to process: document is encrypted");
            }

            InputStream dataStream = d.getDataStream(filesystem);
            return new XSSFWorkbook(dataStream);
        } catch (GeneralSecurityException ex) {
            throw new RuntimeException("Unable to process encrypted document",
                ex);
        }

    }

    private XlsxDecryptor() {
    }

}

E para criação:

public class XlsxEncryptor {

    public static void encrypt(InputStream input, OutputStream output, 
            String password) throws IOException {

        try {
            POIFSFileSystem fs = new POIFSFileSystem();
            EncryptionInfo info = new EncryptionInfo(fs, EncryptionMode.agile);

            Encryptor enc = info.getEncryptor();
            enc.confirmPassword(password);

            OPCPackage opc = OPCPackage.open(input);
            OutputStream os = enc.getDataStream(fs);
            opc.save(os);
            opc.close();

            fs.writeFilesystem(output);
            output.close();
        } catch (GeneralSecurityException e) {
            throw new RuntimeException(e);
        } catch (InvalidFormatException e) {
            throw new RuntimeException(e);
        }

    }

}

Proteção de partes de um documento

O POI implementa a proteção de uma planilha de um documento Excel e a proteção de células. Testei apenas a proteção de planilhas.

A implementação é muito simples, basta usar o método protectSheet. Veja o exemplo para o formato XLSX:

XSSFSheet sheet = workbook.createSheet();
sheet.protectSheet("54321");

E agora o equivalente para o formato XLS:

HSSFSheet sheet = workbook.createSheet();
sheet.protectSheet("54321");

Testes e exemplo

Antes de encerrar o artigo, vou acrescentar aqui dois dos testes unitários que implementei de forma que possam servir como exemplo de uso do POI e do meu projeto.

O primeiro cria um novo arquivo XLSX cripgrafado e em seguida lê o mesmo arquivo verificando se o valor foi gravado corretamente:

@Test
public void createXLSXOpenAndModifyProtected() throws IOException {
    System.out.println("createXLSXOpenAndModifyProtected");

    //creates sheet
    XSSFWorkbook workbook = new XSSFWorkbook();
    XSSFSheet sheet = workbook.createSheet();
    sheet.protectSheet("54321");

    XSSFRow row = sheet.createRow(0);
    XSSFCell cell = row.createCell(0);
    cell.setCellValue("Gravado");

    //saves sheet
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    workbook.write(bos);
    bos.close();
    ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());

    new File("target/.output-file/xlsx").mkdirs();
    WorksheetEncryptor.encrypt(
        bis, 
        new FileOutputStream("target/.output-file/xlsx/OpenAndModifyProtected.xlsx"), 
        DocumentType.XML, 
        "54321");
    bis.close();

    //read again and check
    XSSFWorkbook workbook2 = (XSSFWorkbook) WorksheetDecryptor.decrypt(
        new FileInputStream("target/.output-file/xlsx/OpenProtected.xlsx"),
        DocumentType.XML, 
        "54321");
    Assert.assertEquals("Gravado", workbook2.getSheetAt(0).getRow(0).getCell(0).getStringCellValue());
}

Em seguida, o segundo lê um arquivo XLS criptografado e verifica o valor da célula:

@Test
public void testOpenAndModifyProtectedXLS() throws IOException {
    System.out.println("### testOpenAndModifyProtectedXLS");
    HSSFWorkbook workbook = (HSSFWorkbook) WorksheetDecryptor.decrypt(
        getClass().getResourceAsStream("xls/OpenAndModifyProtected.xls"),
        DocumentType.LEGACY, 
        "12345");
    String conteudoCelula = workbook.getSheetAt(0).getRow(0).getCell(0)
        .getStringCellValue();
    Assert.assertEquals("Teste criptografia", conteudoCelula);
}

Código-fonte

Todo o código, inclusive os testes, está disponível em um projeto no meu GitHub.

Com o Maven você será capaz de executá-lo sem nenhuma configuração adicional. Basta clonar o repositório.

Instalando e configurando o Ubuntu linux numa máquina virtual

virtualbox-ubuntu

Neste tutorial, vamos instalar o Ubuntu, uma das distribuições linux mais populares da atualidade, numa máquina virtual.

Você poderá usar isso para várias finalidades. Aqui no blog, em breve, usaremos em artigos sobre Hadoop e Big Data.

Virtualização

Para quem não está acostumado com virtualização, uma máquina virtual (Virtual Machine, em Inglês) é um ambiente que simula um computador, com sistema operacional próprio, mas que você pode executar dentro do seu sistema atual.

Isso significa que você pode executar um sistema operacional linux dentro do seu Windows e vice-versa. Eu mesmo uso primariamente o Windows 7, mas tenho imagens com XP e diversas distribuições linux.

O sistema operacional principal da máquina é chamado de hospedeiro (host). Os sistemas operacionais usados dentro de máquinas virtuais no sistema hospedeiro são chamadas de sistemas convidados (guests).

Essa técnica tornou-se viável num passado não tão distante quando o hardware atingiu um bom nível de eficiência, inclusive hoje com tecnologia que torna a virtualização quase tão eficiente como um sistema tradicional.

A virtualização traz vários benefícios. O principal é possibilitar a criação da tão famigerada computação em nuvem (cloud computing). Além disso, as empresas que dependem de infraestrutura de TI tanto para desenvolvimento quanto para produção podem usufruir de maior facilidade para a criação de novos ambientes e servidores virtuais, além de flexibilidade para o gerenciamento. Desenvolvedores ou mesmo usuários domésticos como eu podem ter vários servidores com diferentes tecnologias em seu notebook pessoal, inicializados apenas de acordo com a demanda.

Existem ainda sites que disponibilizam ambientes com diversas tecnologias prontos para os administradores usarem em servidores. Um deles é o TurnKey Linux. Baixando imagens de discos virtuais relativamente pequenas, você tem um sistema pronto para uso e somente com o que é necessário para executar a tecnologia escolhida. Enfim, você pode ter um servidor pronto em uma máquina virtual em apenas alguns minutos.

VirtualBox ou VMWare Player?

Os programas gratuitos de virtualização para usuários domésticos mais conhecidos são o VirtualBox da Oracle e o VMWare Player. Ambos são bons produtos, maduros e em constante evolução. Mas com funcionalidades específicas um pouco diferentes, além de vantagens e desvantagens.

Como sou usuário de ambos posso dizer que na prática não há um ganhador absoluto. Depende do uso que fizermos deles. O VMWare, por exemplo, permite copiar e copiar um arquivo do sistema hospedeiro para o convidado e vice-versa. O VirtualBox, por sua vez, traz várias funcionalidades que o VMWare só disponibiliza na versão paga.

Para quem faz questão de uma solução mais completa e possui condições de arcar com as despesas, o melhor seria adquirir uma versão paga do VMWare. Já o usuário doméstico que está começando se dará muito bem com qualquer versão gratuita.

Aqui usaremos o VirtualBox. Mas se alguém optar pelo concorrente não encontrará tanta dificuldade em atingir o mesmo objetivo.

Funcionalidades interessantes do VirtualBox

Existem algumas funcionalidades bem legais quando usamos uma máquina virtual. Irei descrever algumas nas próximas linhas que estão disponíveis no VirtualBox.

Por exemplo, você pode pausar uma máquina virtual a qualquer momento através do menu Máquina > Pausar.

Também é possível salvar snapshots da máquina através do menu Máquina > Criar Snapshot. Sabe o que significa isso? Ao criar um snapshot, você tira uma “fotografia” ou “instantâneo” do sistema naquele momento. Então pode “pintar e bordar”, realizar testes, instalação de programas ou até vírus. Quando cansar da brincadeira, basta restaurar o snapshot e o sistema (disco e memória) voltarão ao estado salvo como se nada tivesse acontecido.

Caso em algum momento você deixe a máquina virtual em tela cheia ou o cursor do mouse seja capturado por ela de forma que você não consiga sair, não se desespere. A tela usada para liberar o mouse e também para algumas teclas de atalho é o CTRL da direita do seu teclado. Este é o padrão e você pode mudá-lo. Essa tecla especial é chamada tecla do hospedeiro, isto é, que permite acessar comandos no sistema hospedeiro. Por exemplo, CTRL+F alterna a máquina virtual entre modo de tela cheia e janela.

Outra funcionalidade interessante, embora deva ser usada com cuidado, é o modo Seamless. Com ele, os programas abertos no sistema dentro da máquina virtual “misturam-se” com a área de trabalho do sistema hospedeiro, dando a impressão de haver apenas um sistema operacional. Veja o seguinte exemplo de um terminal aberto no Ubuntu e exibido em seamless mode:

seamless-mode

Configuração de Hardware

Máquinas mais novas, como o Intel i7, possuem suporte em nível de hardware para virtualização. Entretanto, até algum tempo atrás essas capacidades eram desativadas por padrão. Isso chegava a impedir a virtualização de sistemas operacionais convidados de 64 bits.

Leia o manual da sua placa mãe e do seu processador e verifique se eles possuem suporte nativo para virtualização. Procure por algo como VT-x (Intel) ou AMD-V. Veja um exemplo da BIOS para um processador AMD:

5x3YW

E aqui outro exemplo para um processador Intel:

bios_enablt_vtx1

Lembre-se, sem o suporte nativo, você não será capaz de instalar um sistema operacional de 64 bits como convidado no VirtualBox. Entretanto, se não estou enganado, o VMWare consegue emular via software a virtualização de sistemas 64 bits, mas de qualquer forma o desempenho será sofrível.

Instalando o VirtualBox e as extensões

Acesse a página de downloads e baixe a versão correspondente ao seu sistema operacional.

dowload-virtualbox

Baixe também as extensões para o sistema convidado.

dowload-virtualbox-extension

As extensões trarão várias facilidades, tais como: redimensionamento automático da tela, melhor integração do mouse, compartilhamento de pastas automático entre o sistema hospedeiro e o convidado, uso da USB dentro da máquina virtual e muito mais.

Execute o primeiro arquivo baixado para instalar o VirtualBox. Em geral você não precisa alterar nenhuma configuração, então simplesmente avance até o final da instalação

virtualbox-install

Confirme ainda a instalação de todos os drivers, que serão usados para integrar seus dispositivos como mouse, teclado e rede com a máquina virtual.

Após concluir, execute também o outro arquivo para instalar as extensões do convidado (Guest Additions). O nome deve ser algo como Oracle_VM_VirtualBox_Extension_Pack-4.3.12-93733.vbox-extpack. O programa VirtualBox será aberto. Aceite o contrato para concluir a instalação.

Dando tudo certo, não se esqueça que o atalho adicionado no Menu Iniciar é “Oracle Virtual Box”.

virtualbox-open

Criando uma máquina virtual

Na tela principal do VirtualBox, clique no botão Novo.

virtualbox-main

Na tela de criação, digite “Ubuntu 14”. Note que os demais campos serão preenchidos automaticamente.

configure-vm-01

Clique em Próximo e selecione a quantidade de memória para seu novo ambiente. Aqui vou deixar com 2 Gigabytes (2048 Megabytes), mas uma dica é não ultrapassar 50% da memória total do seu computador.

configure-vm-02

Clique em Próximo. Nesta tela, você poderá criar um novo disco rígido virtual. Um HD virtual é simplesmente um arquivo grande que ficará no seu sistema de arquivos, o qual funcionará como se fosse um HD para o sistema da máquina virtual. A não ser que tenha outros planos, deixe marcada a opção para criar um disco novo.

configure-vm-03

Clique em Criar. Na próxima tela, você poderá escolher o formato do arquivo desse novo disco. Vamos deixar o formato nativo do VirtualBox, o VDI.

configure-vm-04

Clique em Próximo. Nesta tela você pode escolher entre duas opções:

  1. Dinamicamente alocado: nesta opção, o arquivo do disco virtual vai aumentando de tamanho somente quando novos arquivos forem gravados. Isso significa que se você criar um disco de 30 Gigabytes, mas a instalação do SO e os demais arquivos ocuparem apenas 2 Gigabytes, então o arquivo terá apenas 2 Gigabytes. O disco vai aumentando de tamanho na medida do uso até alcançar o limite de 30 Gigabytes.
  2. Tamanho fixo: nesta opção, um disco virtual de 30 Gigabytes vai ocupar todo esse tamanho no seu disco verdadeiro.

Já que economizar espaço nunca é demais, vamos deixar a primeira opção selecionada.

configure-vm-05

Clique em Próximo. Agora vamos selecionar o nome do arquivo e o tamanho do disco virtual.

configure-vm-06

Caso tenha mais de uma partição ou HD no seu computador, você pode mudar o local do arquivo do disco virtual. Em algumas situações já criei máquinas virtuais no meu HD externo. Porém, para este tutorial, vamos apenas deixar tudo como está, pois o padrão é suficiente.

Finalmente, clique em Criar.

Agora você tem um computador virtual para brincar!

virtualbox-virtualmachine-created

Instalando o Ubuntu

Antes de mais nada, acesse a página de downloads da versão desktop do Ubuntu e baixe a versão adequada para o seu computador. Neste tutorial, fiz o download da versão 64 bits, cujo nome do arquivo baixado é ubuntu-14.04-desktop-amd64.iso e possui 964 Megabytes.

ubuntu-download

Com a imagem do disco de instalação do nosso novo sistema operacional, podemos então iniciar a máquina virtual e a instalação.

Na tela principal, selecione a VM (máquina virtual) criada e clique em Iniciar.

Antes da inicialização da VM, o VirtualBox vai saudá-lo com uma tela solicitando o disco de boot. Isso ocorre porque ele verificou que o disco virtual está vazio.

Clique no botão à direita do campo e selecione o arquivo do Ubuntu anteriormente baixado.

vm-boot-disk-select

Clique em Iniciar e aguarde a inicialização da instalação do Ubuntu.

ubuntu-install-01

Você pode selecionar sua língua materna ou deixar em Inglês. Eu prefiro o Inglês porque em TI as traduções acabam por confundir mais que ajudar. Clique em Install Ubuntu ou Instalar Ubuntu, dependendo da sua escolha.

A próxima tela irá informar se o Ubuntu vai executar bem na máquina onde está sendo instalada. Além disso, há opções para já instalar as últimas atualizações e alguns softwares de terceiros. Selecione todas as opções e clique em Continue.

ubuntu-install-02

Agora há opções para formatar ou particionar o disco antes da instalação. Como temos um disco virtual dedicado, simplesmente selecione a primeira opção para formatá-lo e executar uma instalação limpa.

ubuntu-install-03

Clique em Install Now.

Na verdade, a instalação não vai começar ainda. Isso deve ter sido uma grande falha de design. A próxima tela contém a seleção da sua localidade. Digite o nome da capital do seu estado. Coloquei “Sao Paulo”.

ubuntu-install-04

Clique em Continue.

Na próxima tela você pode selecionar o tipo do seu teclado. Teste-o para ver se está ok e clique novamente em Continue.

ubuntu-install-05

Finalmente, digite seus dados de usuário, incluindo a senha, e clique em Continue para iniciar a instalação de verdade.

ubuntu-install-06

Aguarde o processo de instalação.

ubuntu-install-07

Ao final, uma caixa de diálogo vai aparecer informando que o sistema deve ser reiniciado. Clique em Restart Now.

Nota 1: enquanto fazia este tutorial, o Ubuntu travou e não reiniciou corretamente. Então, fui até o menu Máquina > Reinicializar para forçar um reset.

Nota 2: a instalação do Ubuntu ejetou automaticamente o disco de instalação virtual do Ubuntu. Se estiver instalando outro sistema operacional que não faça isso, use o menu Dispositivos > Dispositivos de CD/DVD > Remover disco do drive virtual para não iniciar a instalação do sistema novamente por engano.

Pronto, o sistema está instalado e pronto para uso.

ubuntu-installed

Melhorando a integração entre sistema hospedeiro e convidado

Note que a janela do ubuntu ficou bem pequena, quase inutilizável. Vamos resolver isso!

Lembra que instalamos as “extensões do convidado” (Guest Additions) no VirtualBox? Elas facilitarão o uso da máquina virtual de várias formas, mas falta a parte da instalação no sistema convidado. Isso ocorre para que o VirtualBox consiga “conversar” com o SO que está na máquina virtual.

Para fazer isso, devemos seguir as instruções da documentação do VirtualBox que nos dá alguns comandos.

Vamos abrir o terminal de comandos clicando no primeiro botão à esquerda (equivalente ao “Iniciar” do Windows) e pesquisando na caixa de busca por “terminal”.

search-terminal

Se nada mudou no VirtualBox ou no linux desde que escrevi este tutorial, as instruções do Guest Additions para o Ubuntu consistem nos seguintes comandos:

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install dkms

Nota: um usuário comentou que não conseguiu executar o último comando com sucesso, tendo substituído por sudo apt-get install virtualbox-guest-dkms. Isso pode ser necessário se estiverem sendo usadas diferentes configurações ou outras versões do Ubuntu ou ainda outras distribuições linux.

O comando sudo que prefixa os demais não está na documentação, mas é necessário se você não está executando o terminal com privilégios de superusuário (administrador).

O primeiro comando é apt-get update. Ele irá atualizar o índice de pacotes do Ubuntu. Dessa forma ele saberá as últimas versões de todos os seus componentes e programas. Após digitar o comando, o sistema irá solicitar a senha do usuário e então executar a ação.

guest-additions-01

O próximo comando é apt-get upgrade. Ele vai efetivamente instalar todas as atualizações do sistema. Após entrar o comando, o Ubuntu vai solicitar algumas confirmações. Pressione Y (yes) para confirmar a atualização e aguarde.

guest-additions-02

Após a atualização do sistema, executaremos o último comando: apt-get install dkms. Este comando vai instalar o pacote dkms, que possibilita a módulos do kernel serem atualizados independentemente. O Guest Additions precisa disso porque ele é um módulo do Kernel e é atualizado com frequência, caso contrário seria necessário recompilar o Kernel do linux a cada atualização.

guest-additions-03

O comando vai pedir a confirmação da instalação. Pressione Y quando necessário.

Neste momento já cumprimos todos os pré-requisitos para a instalação do Guest Additions. Então vamos à instalação em si.

Acesse o menu Dispositivos > Inserir imagem de CD dos Adicionais para Convidado....

guest-additions-04

Ao acionar o menu, uma imagem de CD do VirtualBox será montada no sistema do Ubuntu e a execução automática (auto run) ocorrerá. Uma mensagem de confirmação será exibida.

guest-additions-05

Clique em Run. A senha será novamente solicitada. Digite-a e aguarde o final da instalação.

guest-additions-06

Finalmente, vamos reiniciar o sistema para ativar o módulo que acabamos de instalar. Clique no botão do sistema no canto superior direito do Ubuntu e selecione a opção Shut Down....

guest-additions-07

Na tela que vai abrir, clique no botão da esquerda para reiniciar.

Após a reinicialização, você poderá, entre outras coisas, redimensionar a janela do VirtualBox como quiser e o Ubuntu irá se ajustar a esse tamanho. Legal, né? Esta é a opção Visualizar > Redimensionar Tela Automaticamente que estava desabilitada anteriormente, mas agora veio ativada por padrão.

Palavras finais

Virtualização é um conceito importantíssimo no mundo de hoje. Desenvolvedores de software não precisam ser especialistas em virtualização, mas devem ter bons conceitos sobre como isso funciona e devem saber usar todos os benefícios a seu favor.

Criar máquinas virtuais não é difícil, basta ter uma base sobre o assunto e saber usar as ferramenta já existentes, que estão cada vez mais intuitivas e poderosas.

Os benefícios da criação de máquinas virtuais são inúmeros, a começar por podermos usufruir de uma variedade de ambientes dentro de um único computador.

Em futuros artigos, pretendo trazer tutoriais envolvendo Hadoop, inclusive com a criação de um cluster, cada um em uma máquina virtual, para processamento Big Data.

Página 3 de 8

Creative Commons O blog State of the Art de Luiz Ricardo é licenciado sob uma Licença Creative Commons. Copie, compartihe e modifique, apenas cite a fonte.