evoluindo - univale · mesmo individualmente, para que nos forneçam uma per-cepção de atenção,...

7
14 : : www.mundoj.com.br : : o design e arquitetura através das métricas do Evoluindo Sonar O Design Emergente é uma prática ágil para identificar padrões comuns que são identificados, emergidos, ao longo de um desenvolvimento ágil. O objetivo deste artigo é apresentar como podemos identificar esses padrões a partir do monitoramento contínuo da qualidade dos códigos-fonte de projetos com os indicadores e informações providas pela ferramenta Sonar. Como extrair métricas do Sonar para identificar design emergente e melhorar continuamente a qualidade do seu pro- jeto de software. 14

Upload: others

Post on 29-May-2020

2 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Evoluindo - Univale · mesmo individualmente, para que nos forneçam uma per-cepção de atenção, grandeza, esforço e se algo é bom ou ruim. Por exemplo, a informação que uma

14

: : www.mundoj.com.br : :

o design e arquitetura através das métricas do

Evoluindo

Sonar

O Design Emergente é uma prática ágil para identificar padrões comuns que são identificados, emergidos, ao longo de um desenvolvimento ágil. O objetivo deste artigo é apresentar como podemos identificar esses padrões a partir do monitoramento contínuo da qualidade dos códigos-fonte de projetos com os indicadores e informações providas pela ferramenta Sonar.

Como extrair métricas do Sonar para

identificar design emergente e melhorar

continuamente a qualidade do seu pro-

jeto de software.

14

Page 2: Evoluindo - Univale · mesmo individualmente, para que nos forneçam uma per-cepção de atenção, grandeza, esforço e se algo é bom ou ruim. Por exemplo, a informação que uma

15

Breno Barros

([email protected]/Twitter @brenoobarros): é bacharel em Ciência da Computação, possui as certificações SCEA, CSPO, CSM, RUP, IBM SOA Solution Designer. É arquiteto de soluções da Stefanini IT Solutions há cerca de 5 anos, onde atua como líder do Centro de Excelência SOA e do Escritório de Arquitetura e Práticas Ágeis da filial de Belo Horizonte.

m uma abordagem de desenvolvimento ágil, o sof-tware ou produto vai ganhando forma a cada entrega realizada. Mas isto não quer dizer que não devemos

nos preocupar com a arquitetura do software. Não importa se o projeto de software tem escopo, custo ou prazo variável. A qua-lidade deve ser sempre uma constante. Ou seja, ser ágil é primar pela qualidade interna e externa dos códigos. Ser ágil é se preo-cupar com a arquitetura e projeto da solução em todo e qualquer momento (Just-in-Time).

A arquitetura de software é o alicerce para a construção de uma solução robusta. Fazendo uma analogia com um processo de construção de uma pirâmide, os elementos arquiteturais de sof-tware são como os blocos de pedra que irão compor a base de

uma pirâmide. Com este alicerce totalmente definido e constru-ído, pode-se colocar os blocos de pedra adicionais nos degraus superiores até que a pirâmide esteja totalmente concluída. Retor-nando ao mundo do software, estes blocos de pedra adicionais são os elementos de design (classes, relacionamentos, dentre outros). Porém, pode ocorrer que ao final ou próximo do final da cons-trução da pirâmide, um ou mais blocos da base necessitam ser trocados, pois não suportarão a estrutura imaginada da pirâmide. Com isto, um retrabalho enorme e não planejado acaba de surgir. É isto que acontece quando se define a arquitetura de uma solução totalmente, sem ter um conhecimento completo e consistente de suas reais necessidades. O segredo para evitar o problema exposto acima é construir os elementos de arquitetura de modo que sejam mais fáceis de substituir caso sejam necessário em algum momen-

Page 3: Evoluindo - Univale · mesmo individualmente, para que nos forneçam uma per-cepção de atenção, grandeza, esforço e se algo é bom ou ruim. Por exemplo, a informação que uma

16

: : www.mundoj.com.br : :

to futuro. Mas como fazer isso? É aqui que a adoção da prática de Design Emergente será muito útil.

Este artigo faz uma breve introdução sobre a prática ágil de design emergente para guiar uma arquitetura consistente e evolutiva, confrontando-a com os malefícios da prática convencional de se definir a arquitetura total antes do início da codificação e desta-cando a sua importância para conseguirmos o real sucesso em nossos projetos. Em seguida será apresentada a ferramenta Sonar e como extrair continuamente indicadores e métricas (duplicação de códigos, complexidade ciclomática e acoplamento aferente, dívida técnica, conformidade de requisitos não-funcionais e de-pendências cíclicas) para identificarmos os padrões de projeto comuns e aprimorarmos nossa arquitetura. Outras práticas para identificação de design emergente, como Test-Driven Develope-ment (TDD), não serão abordados neste artigo.

Entendendo o Design Emergente

Os arquitetos ou projetistas, praticantes de métodos de desenvolvimen-to de software no ciclo-de-vida em cascata, gastam muito tempo no início do projeto tentando documentar todos os elementos de projeto da solução, os famosos mecanismos arquiteturais. Esta abordagem de design é conhecida como Big Design Up Front e tem como consequên-cia o atraso no início da codificação do software em questão.

Além disso, sabemos que no início de um projeto de software o nível de incertezas sobre como os requisitos serão mais bem implementados é muito alto. À medida que os elementos de projeto vão sendo imple-mentados, surgirão acoplamentos entre eles e aspectos do código-fonte que antes pareciam insignificantes aumentarão em complexidade a cada incremento de código, naturalmente. Com isto, certamente al-gumas surpresas irão surgir quando a codificação iniciar, resultando em uma enorme desatualização e retrabalho nos elementos de design definidos e documentados no início do projeto.

Já os praticantes de métodos ágeis, conhecendo os níveis de incerteza e por trabalharem de forma iterativa e incremental, buscam adiar até o último momento responsável, quando se tem melhor entendimento do que se precisa, para tomar as decisões de design que terão implicações em longo prazo de forma clara e assertiva. Esta abordagem de design é conhecida como Design Emergente.

A essência da prática de Design Emergente compreende que ao adiar as decisões importantes sobre arquitetura e projeto até o último momento responsável, é possível impedir a complexidade desnecessária origina-da da subavaliação dos projetos de software.

A aplicação da prática de Design Emergente, adiando as decisões para último momento responsável, tem um custo. Porém, este custo ainda é bem menor que o trazido pelas más decisões ou pelas decisões su-perficiais.

Em suma, na prática Big Design Up Front é a arquitetura que direciona o design, o que engessará e muito a solução. Enquanto na prática de Design Emergente é o design que direciona a arquitetura, tornando-a evolutiva, enxuta, eficiente e flexível.

O que é necessário para adotar o Design Emergente

quais as metas e resultados esperados com o projeto.

-ras e objetivas para cada iteração do seu projeto.

-deram o que deve ser feito.

de desenvolvimento, por mais jovem que seja, já vivenciou alguma experiência em projetos passados que pode ajudar no direcionamento técnico do projeto.

-madores de seus times sozinhos. Não basta dar um documen-to ou diagramas de classes e de colaboração e esperar que saia um ótimo resultado.

-tos nunca são demais, desde que tenha propósitos claros.

e Adaptação.

Sonar

O Sonar é uma plataforma Web aberta para gerenciar a qualidade de código, oferecendo indicadores e métricas sobre a qualidade dos códigos-fonte de seus projetos. As métricas que o Sonar abrange por padrão são: arquitetura e projeto, complexidade, testes unitá-rios e cobertura de códigos, potênciais bugs, comentários de docu-mentação, duplicações de códigos e diretrizes de codificação (por exemplo, convenções de nomenclatura, detecção de anti-patterns, dentre outros). Outras métricas são obtidas através de plug-ins,

de um projeto, com esses indicadores e métricas, na figura 1.

Figura 1. Painel de controle de métricas fornecidas pelo Sonar.

Os pilares de qualquer abordagem ágil são: Transparência, Inspeção e Adaptação. Estes pilares são estruturas fractais que devem ir desde a macrogestão do projeto (relacionamento com clientes, melhor uso dos recursos financeiros, planejamento de releases, dentre outros) até o microgerenciamento (comunicação entre membros do time, esti-mativas, execução das tarefas) e os artefatos de softwares produzidos (códigos e artefatos de configuração). O Sonar pode ajudar em todos esses níveis, conforme veremos neste artigo.

Outra grande vantagem do Sonar é que além da linguagem Java, ele suporta outras linguagens: .NET, PHP, PL/SQL, Flex/Action Script,

Page 4: Evoluindo - Univale · mesmo individualmente, para que nos forneçam uma per-cepção de atenção, grandeza, esforço e se algo é bom ou ruim. Por exemplo, a informação que uma

17

A adoção da prática de design emergente nos leva a encontrar padrões comuns em códigos existentes e garantir a qualidade da arquitetura e design. Mas como fazer isso? Uma técnica é o uso de uma combina-ção de métricas. E é nesse ponto que Sonar poderá nos ajudar. Iremos a partir de agora focar em como extrair essas informações do Sonar, focando nas seguintes métricas: duplicação de códigos, complexida-de ciclomática e acoplamento aferente, dívida técnica, conformidade de requisitos não-funcionais e dependências cíclicas.

Métricas de Software

As métricas no mundo físico (por exemplo: centímetros, metros, litros, dentre outras) são significantes o suficiente, mesmo individualmente, para que nos forneçam uma per-cepção de atenção, grandeza, esforço e se algo é bom ou ruim. Por exemplo, a informação que uma faixa de sinaliza-ção com comprimento de 2 quilômetros deve ser pintada em uma rua é o suficiente para sabermos o quanto de esforço e tempo será necessário para realizar o trabalho. Já no caso dos softwares, por não serem físicos, as métricas de software somente fazem sentido quando comparadas. Por exemplo, informar que a métrica de complexidade ciclomática de uma classe é igual 9, não provê uma visão clara se isso é bom ou ruim. Porém, quando dizemos que a complexidade ciclomática da classe A é igual a 9 e que da classe B é igual a 20, sabemos que devemos focar nossos esforços na classe B, pois ela está com uma complexidade mais alta.

Duplicação de código

A duplicação de códigos é o primeiro sintoma que informa que o design não está nada bom. As duplicações de códigos surgem naturalmente, principalmente quando os desenvolvedores acham que não têm outra escolha, ou não percebem que estão duplican-do informações, ou ficam com preguiça e duplicam porque parece mais fácil.

A duplicação de códigos é responsável por um aumento desneces-sário da complexidade, alto grau de dependência, ou acoplamento, e baixa coesão, sem falar no trabalho despendido adicional, já que poderíamos ter reusado os tais fragmentos de códigos duplicados.

Com tudo isso, evitar a duplicação de código não é tarefa fácil. Mais existem duas soluções, que combinadas, ajudam e muito nesta tarefa árdua. A primeira é promover entre os membros da equipe, uma comunicação ativa e frequente (métodos ágeis nos trazem excelentes práticas). A segunda é monitorar constante-mente os nossos códigos. E é nesta que o Sonar pode nos auxiliar e muito.

Conforme podemos ver na figura 2, o Sonar oferece uma forma rápida para identificar os pacotes e classes com códigos dupli-cados, com uma ordenação dos pacotes e classes com maiores quantidades de duplicação. Selecionando uma classe específica, podemos analisar na aba Duplications os fragmentos de códigos que estão duplicados e a partir deles identificar os padrões de pro-jeto para remover essas duplicações e planejar suas refatorações.

Figura 2. Inspeção de códigos duplicados no Sonar.

Os padrões de projeto da Gang of Four (GoF) e do Catálogo de Padrões de Refactoring, proposto por Martin Fowler e colabora-dores, são excelentes para sanar os problemas de duplicação de códigos. Este último apresenta padrões como: Extract Method, Extract Interface, Extract Class, Consolidate Conditional Expres-sion, Consolidate Duplicate Conditional Fragments e Decompose Conditional, são bem voltados para remover as duplicações.

Complexidade Ciclomática e Acoplamento Aferente

A Complexidade Ciclomática, também conhecida como Métrica McCabe (pois foi criada por Thomas J. McCabe), consiste em uma medida da complexidade relativa de um método em relação a outro.

Para se chegar à complexidade ciclomática na linguagem Java, o Sonar utiliza uma contagem (incremento de 1 em 1) de instruções (if, for, while, case, catch, throw, return, &&, ||, ?) em cada méto-do das classes do projeto, com exceção dos métodos getters, que

Listagem 1. Exemplo de cálculo da complexidade ciclomática no Sonar.

//Listagem 1. Exemplo de cálculo da complexidade ciclomática no Sonar.

public boolean realizarSaque(Conta conta, Double valor) throws SaldoInsufi-cienteException{ // +1 if(conta.getSaldo() >= valor){ // +1 conta.setSaldo(conta.getSaldo() - valor); } else{ // +1 throw new SaldoInsuficienteException(); // +1 } return true; // +1}

Já o Acoplamento Aferente representa a contagem de quantas classes diferentes usam a classe corrente (aquela que está sendo analisada). Já o Acoplamento Eferente constitui a contagem de quantas classes diferentes são usadas pelas classes correntes.

Individualmente, as métricas de complexidade ciclomática e acoplamento aferente provêem informações significantes para me-lhorar o design de softwares. Porém, juntas, trazem uma excelente

Page 5: Evoluindo - Univale · mesmo individualmente, para que nos forneçam uma per-cepção de atenção, grandeza, esforço e se algo é bom ou ruim. Por exemplo, a informação que uma

18

: : www.mundoj.com.br : :

visão sobre o que deve ser priorizado, caso o fator tempo seja algum obstáculo para uma refatoração completa dos fragmentos de códi-go. Por exemplo, dado que em algum momento de entrega parcial de um projeto de software, existem muitos códigos com alta com-plexidade, e o tempo para reduzir essa complexidade para todos os códigos está curto, a métrica de Acoplamento Aferente será um grande aliado, pois os códigos que possuem maior índice de aco-plamento aferente são mais usados. Logo, os códigos que possuem maiores complexidades ciclomáticas e acoplamentos aferentes são os que devem sofrer um processo de refatoração primeiro.

Estudos têm mostrado que códigos com um valor de complexidade igual a 11 têm menor probabilidade de serem propensos a falhas (cerca de 28%). Códigos com a complexidade no valor de 38 pos-suem uma probabilidade de 50% de estarem propensos a falhas. Já códigos com complexidade no valor 74 ou mais possuem altas probabilidades de ocorrerem falhas (98%).

Figura 3. Inspeção complexidade e acoplamento aferente no Sonar.

A figura 3 mostra os indicadores de Complexidade do Sonar (acessí-vel na opção Hotspots no menu lateral esquerdo) exibindo as classes com maiores complexidades. Clicando em cada uma delas, podemos analisar na aba Dependencies qual tem maior acoplamento aferente. Neste exemplo, apesar da classe ModuleImpl possuir maior comple-xidade em relação a classe SecureAction, a classe ModuleImpl possui praticamente a metade da quantidade de acoplamentos aferentes em relação a classe SecureAction. Logo, a classe SecureAction provavel-mente terá maior prioridade em processo de refatoração.

Para evitar o crescimento da complexidade ciclomática nos códigos-fonte, é recomendável a utilização de mecanismos de injeção de dependência. Pois os mesmos permitem criar cadeias de relacio-namentos via metadados, arquivos de configuração, sem incluí-los diretamente no código. Além disso, a adoção da injeção de depen-dência nos permitirá testar cada código de forma independente com testes unitários, e minimizar o aumento da complexidade à medida que novos códigos-fonte vão surgindo durante a codificação de um projeto de software.

Dívida técnica

A dívida técnica é um termo concebido por Ward Cunningham e já bastante conhecido, que é melhor compreendido por meio de uma analogia com um empréstimo financeiro à base de juros. Às vezes, para resolvermos problemas emergenciais devido a um mau planejamento, tomamos a decisão de pegar dinheiro emprestado para “resolver” o problema, mesmo sabendo que teremos que pagar juros altíssimos depois. A dívida técnica é semelhante. Decisões emergen-

ciais são tomadas em projetos de software, normalmente desprezan-do boas práticas e padrões de desenvolvimento, e que a longo prazo resultarão no pagamento de um preço alto por essas decisões.

A dívida técnica pode surgir de diversas situações, dentre elas des-tacamos:

de uma dada solução. Neste caso, de forma proposital o time parte para uma solução provisória, sacrificando a qualidade, para quem sabe um dia retornar e melhorar a solução.

um sistema sem utilização de testes unitários.

os princípios básicos de design e então nem imaginam a “bagun-ça” que estão fazendo.

O Sonar lida com a dívida técnica com base em seis pilares de uma boa codificação: má distribuição da complexidade, duplicações de códigos, falta de comentários, violação de diretrizes de desenvolvi-mento, bugs em potenciais, ausência de testes unitários ou testes unitários inúteis e design ruim.

Para analisar a dívida técnica no Sonar é necessário instalar um plug-in denominado Technical Debit, que com base nos pilares descritos acima, gera os seguintes indicadores (ver figura 4).

Figura 4. Indicadores de dívida técnica no Sonar.

As informações presentes nos indicadores de Dívida Técnica são:-

nica atual do projeto versus o total possível para o projeto.

valor/hora do time, para pagar ou sanar a dívida técnica atual.

jornada de 8 horas de trabalho, fornece a quantidade de dias de trabalho para pagar a dívida, levando em consideração um único desenvolvedor.

gráfico em pizza, distribuindo através dos pilares.

Para detalhes sobre como o cálculo da dívida técnica é pelo Sonar, veja o quadro Cálculo da Dívida Técnica no Sonar.

Uma boa aplicabilidade destes indicadores de dívida técnica é usá-las para demonstrar aos gerentes de projetos, patrocinadores e demais envolvidos os impactos de sacrificarmos a qualidade para atender os famosos cronogramas extremamente apertados. Pois apenas abordar que dada decisão emergencial irá afetar na duplicação de códigos, aumento das dependências, dentre outros problemas, normalmente não fará com que eles tenham a visão des-tes impactos. Porém, quando estes impactos são demonstrados em valores financeiros, ou em dívidas financeiras, eles perceberão que, por ser uma dívida, em algum momento futuro, ela deverá ser paga para garantir a qualidade prometida. E até mesmo decidirem se é melhor fazer a solução emergencial provisória ou investir mais tem-po para projetar uma solução alinhada às boas práticas e padrões de desenvolvimento, que no final das contas sairá mais em conta.

Page 6: Evoluindo - Univale · mesmo individualmente, para que nos forneçam uma per-cepção de atenção, grandeza, esforço e se algo é bom ou ruim. Por exemplo, a informação que uma

19

Cálculo da Dívida Técnica no Sonar

O cálculo da dívida técnica no Sonar é realizado pela soma-tória dos custos para correção das duplicações, correção das violações de diretrizes de desenvolvimento, criação de testes unitários para cobrir códigos descobertos, correção da distri-buição de complexidade dos métodos e classes, remoção das dependências cíclicas entre pacotes e escrita dos comentários nas APIs.

único bloco de código (em horas) x quantidade de blocos duplicados.

única violação (em horas) x quantidade de violações.-

tável = 80%): custo para realizar a cobertura de um único bloco de código (em horas) x quantidade de blocos desco-bertos.

(custo para distribuir a complexidade de um método (em horas) x quantidade de métodos com complexidade maior ou igual a 8) + (custo para distribuir a complexidade de uma classe (em horas) x quantidade de classes com com-plexidade maior ou igual a 60).

-tes: custo para remoção das dependências cíclicas entre dois arquivos (em horas) x quantidade de dependências cíclicas.

uma API (em horas) x quantidade de APIs não comentadas.

Para configurar os parâmetros de cálculo da Dívida Técnica no So-

Figura 5. Tela de configuração da dívida técnica no Sonar.

Figura 6. Indicadores de alguns requisitos não-funcionais no Sonar.

Conformidade de Requisitos Não-Funcionais

Também é possível com o Sonar, monitorar a conformidade de requisitos não-funcionais como: Eficiência, Manutenebilidade,

Dependências cíclicas

A existência de dependências cíclicas entre pacotes e classes é outra

Dependências em excesso são muito ruins. Dependências cíclicas, pior ainda. Principalmente quando estas dependências cíclicas ocor-rem entre pacotes que separam as camadas lógicas de um software, é um sinal de que a arquitetura não está bem projetada. Pois se ter uma boa arquitetura é pré-requisito que uma dada camada inferior desconheça a sua camada superior vizinha, e assim sucessivamente. Somente camadas superiores devem conhecer as camadas inferiores.

Selecionando os indicadores que mostram essas dependências cíclicas, o Sonar exibe os pacotes que possuem dependências

Figura 7. Indicadores de Dependências Cíclicas no Sonar.

Com a seleção de uma dessas dependências cíclicas (pontos em vermelho), o Sonar exibirá quais pacotes estão participando desta violação. A figura 9 traz como exemplo que a dependência cíclica está ocorrendo entre os pacotes org.apache.commons.commons.collections.set e org.apache.commons.commons.collections.list.

Page 7: Evoluindo - Univale · mesmo individualmente, para que nos forneçam uma per-cepção de atenção, grandeza, esforço e se algo é bom ou ruim. Por exemplo, a informação que uma

20

: : www.mundoj.com.br : :

De posse dessas informações de dependências cíclicas, somadas com as métricas de design abordadas acima, testes e cobertura, o Sonar através do plug-in Total Quality proverá um resumo geral da qualidade do projeto e também distribuídas pelos pilares de

Figura 10. Resumo da qualidade do design e

arquitetura do projeto com o plug-in Total Quality

do Sonar.

Com todas essas métricas providas pelo Sonar, as atividades de identificação dos problemas de qualidade e dos padrões emergen-tes são facilitadas e assertivas para o aprimoramento e evolução da arquitetura e projeto, através de refatorações constantes.

Acompanhando a Evolução do seu Design

A utilização contínua do Sonar em projetos de software traz como benefício a capacidade de acompanhamento da evolução dos pa-drões de arquitetura e design, com base em dados históricos exibi-dos em uma linha do tempo (opção Timeline no menu esquerdo). Para análises mais específicas, a linha do tempo pode ser filtrada por até três métricas, entre todas oferecidas pelo Sonar.

Na figura 11 segue um exemplo da linha do tempo de um projeto, filtrada pelas dimensões: Linhas de Código (linha amarela), Dívida Técnica (linha vermelha) e Dependências Cíclicas (linha azul).

Figura 11. Linha do tempo da evolução do um projeto de software no Sonar.

Para Saber Mais

Os conceitos deste artigo foram apresentados por Lucas Sou-za e Paulo Silveira na edição 41 da MundoJ, no artigo “Evo-lução do Design através de Testes e o TDD”. Confira também na edição 33 da MundoJ o artigo de Eduardo Guerra sobre “Refatoração? Melhoria Contínua no Código”.

Considerações finais

As práticas convencionais para definição e documentação total da arquitetura e design antes do início da codificação já se provaram ineficazes há muito tempo. Muitos não entendem porque no final dos projetos de softwares, seguindo um ciclo-de-vida em cascata, muitos problemas surgem na arquitetura e projeto da solução.

A adoção da prática ágil de design emergente, principalmente apoiada por ferramentas de geração de métricas como o Sonar, nos permite inspecionar, adaptar e evoluir continuamente a ar-quitetura e design dos softwares em desenvolvimento. Além de fornecer diversas métricas sobre a qualidade da arquitetura e de-sign, esta prática facilita uma comunicação transparente entre os membros do time e demais envolvidos do projeto. Portanto, o de-sign emergente direciona o programador a garantir uma qualidade constante dos seus códigos, independentemente se seu projeto é

-

DebtQuadrant.html

-

Referências