• Nenhum resultado encontrado

Atividade1

N/A
N/A
Protected

Academic year: 2021

Share "Atividade1"

Copied!
14
0
0

Texto

(1)

Universidade Federal de Pernambuco – UFPE Centro de Informática - CIn

Tópicos Avançados em

Engenharia de Software

Identificar oportunidades de aumento do reuso de código

Dupla

Caio César Sabino Silva (ccss2@cin.ufpe.br) Lais Sousa de Andrade (lsa@cin.ufpe.br)

Professor

Paulo Borba (phmb@cin.ufpe.br)

(2)

Identificar oportunidades de aumento do reuso de código

Este documento tem como objetivo analisar a segunda versão do Research Group Management System. A análise do sistema concerne à identificação de oportunidades de reuso de código e foi realizada com a utilização da ferramenta CCFinder.

Analisando o sistema com o CCFinder

O CCFinder é uma ferramenta utilizada para encontrar clones de trechos de código em diversas partes do software. Trabalhando sobre os parâmetros definidos, a ferramenta auxilia na identificação de que regiões de códigos podem ser consideradas como clones. Após a identificação de tais regiões de códigos com a ferramenta, estes locais podem ser estudados no sentido de se estimar os benefícios e custos de modificação. Com base na análise, as técnicas de reuso de código podem ser aplicadas nos locais onde seja vantajoso aplicar tais alterações no código.

Parâmetros de configuração

Parâmetros iniciais para análise:

● Minimum Clone Length: 50 ● Minimum TKS: 12

● Shaper Level: 2 - Soft shaper ● P-match Application: On ● Prescreening Application: Off

Com tais parâmetros, alguns conjuntos de clones foram encontrados, dos quais certos conjuntos bastante significativos poderam ser observados. Para encontrar outros possíveis clones interessantes, vamos reduzir as restrições:

● Minimum Clone Length: 40 ● Minimum TKS: 10

● Shaper Level: 2 - Soft shaper ● P-match Application: On ● Prescreening Application: Off

Nessa configuração, o número de clones aumentou, entretanto boa parte dos novos clones são trechos muito pequenos. Ainda assim, alguns conjuntos interessantes foram encontrados como o conjunto 14 (não detectado anteriormente por não possuir o tamanho mínimo 50). Uma característica

(3)

interessante nessa análise com restrições reduzidas é a aparição de clones significativos encontrados em uma mesma classe (como Controle), o que pouco ocorreu na análise mais superficial.

Gráfico dos clones

Foram obtidos os seguintes gráficos dos clones (um para cada configuração usada).

(4)

Gráfico obtido na segunda análise

O primeiro gráfico notavelmente possui menos linhas pretas, e fica melhor de observar alguns clones significativos como o da direita perto da linha central, que é um dos clones mais significativos encontrados.

Já o segundo gráfico possui mais linhas pretas, inclusive notavelmente se percebe um quadrado preto próximo ao canto superior esquerdo, que embora pareça um clone bastante relevante, se trata de condições de if que verificam se vários campos do tipo String são válidos, havendo repetição nas comparações se tal String é null ou vazia. O impacto de tal repetição não é tão grave, uma vez que acontece dentro de uma mesma classe em locais pequenos, mais precisamente, ocorre dentro de uma

(5)

condição de if. Sendo assim, não é tão prejudicial quanto outros pontos que parecem menos relevante. Esse clone será detalhado posteriormente.

Vale ressaltar que no segundo gráfico ocorrem mais casos de clones em uma mesma classe, o que é raro no primeiro gráfico. Com menos restrições, foi possível também observar uma boa quantidade de clones que ocorriam em subclasses de classes como Controle ou Dao que poderiam ser solucionadas através da inclusão de métodos adicionais na superclasse que poderia reduzir bastante o código nos subtipos. Exemplos como esse serão detalhados posteriormente.

Quantidade de clones encontrados

Na primeira análise foram encontrados 22 conjuntos de clones. Já na análise menos restrita, foram encontrados 39 conjuntos de clones.

Com o CCFinder, é possivel observar métricas de cada conjunto de clone sem ter que olhar individualmente cada um. O critério de quão significativo é o clone é relativo. Inúmeros fatores contribuem para o quão relevante um clone é considerado, como o fato de ocorrer múltiplas vezes, em várias classes, estar muito espalhado, conter loops, possuir um tamanho muito grande. Mas com o CCFinder, pode-se facilmente identificar pela interface as métricas no qual cada conjunto se sobressai ou não, como podemos ver na imagem abaixo:

Algumas métricas de alguns conjuntos de clones

Dessa forma, se considerarmos o tamanho do clone como o indicador de relevância, podemos observar na segunda análise, 8 conjuntos de clones relevantes, pois contêm métrica LEN indicada de vermelho. Já se consideramos como fator mais relevante o fato de o código ocorrer múltiplas vezes, vemos, graças à métrica POP, que 2 conjuntos de clones são considerados relevantes. Isso funciona como um segundo filtro que facilita a busca, no gráfico, dos clones que são de fato relevantes.

(6)

O gráfico de clones e as métricas ajudam a filtrar as regiões de código mais propicias de ter repetição de código relevante. Mas ainda assim alguns aspectos que determinam a relevância de um clone devem ser verificados no código. Entre tais aspectos, podem ser citados o impacto que se tem em termos de operações a serem realizadas para solucionar tal redundância e se tais operações prejudicam algum fator de qualidade do software, como extensibilidade ou outro. Dessa forma, alguns clones significativos serão analisados abaixo, verificando o impacto que as mudanças para eliminar tal repetição podem causar.

Exemplo 1 - Conjunto 42

Este conjunto possui o segundo maior LEN (215) e o maior TKS (27) e envolve três métodos de duas classes. Segue o código nas duas classes:

br.ufpe.cin.rgms.publicacao.apresentacao.AlterarDadosPublicacaoServlet.java

private void processUploadedFile(FileItem item) { if (item.getContentType() != null) {

this.pdfFile = item.get(); }

}

private void processFormField(FileItem item) { // Process a regular form field

if (item.isFormField()) {

String name = item.getFieldName(); String value = item.getString();

this.formfields.put(name, value); }

}

public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {

// Create a factory for disk-based file items

FileItemFactory factory = new DiskFileItemFactory();

// Create a new file upload handler

ServletFileUpload upload = new ServletFileUpload(factory);

(7)

List /* FileItem */items = upload.parseRequest(request);

// Process the uploaded items Iterator iter = items.iterator();

while (iter.hasNext()) {

FileItem item = (FileItem) iter.next();

if (item.isFormField()) { processFormField(item); } else { processUploadedFile(item); } }

String titulo = this.formfields.get("titulo");

String ano = this.formfields.get("ano");

br.ufpe.cin.rgms.membro.apresentacao.AlterarDadosMembroServlet.java

private void processUploadedFile(FileItem item) { if(item.getContentType() != null){

this.foto = item.get(); }

}

private void processFormField(FileItem item) { // Process a regular form field

if (item.isFormField()) {

String name = item.getFieldName(); String value = item.getString();

this.formfields.put(name, value); }

}

public void doPost( HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {

(8)

FileItemFactory factory = new DiskFileItemFactory();

// Create a new file upload handler

ServletFileUpload upload = new ServletFileUpload(factory);

try {

List /* FileItem */ items = upload.parseRequest(request);

// Process the uploaded items Iterator iter = items.iterator();

while (iter.hasNext()) {

FileItem item = (FileItem) iter.next();

if (item.isFormField()) { processFormField(item); } else { processUploadedFile(item); } }

String nome = this.formfields.get("nome");

String sobrenome = this.formfields.get("sobrenome");

Esse conjunto é interessante pelo fato de possuir uma boa quantidade de código replicado. Entretanto a replicação ocorre em somente uma outra classe. O método post possui literalmente o mesmo começo do outro e é um trecho consideravelmente grande. O custo de alteração de código nesse caso poderia se reduzir a um simples refatoramento, no qual poderia se extrair um método numa classe auxiliar que faria o código repetido. O primeiro e o segundo método podem ser alterados utilizando uma superclasse com os atributos (só diferem pelo nome) e os métodos em comum. Ou seja, técnicas simples de refatoramento conseguem eliminar a redundância de uma boa quantidade de código sem implicar em mudanças estruturais graves no software.

Ainda, se for considerado apenas o método processFormField, a replicação se estende a mais outra classe. Portanto, tratando este problema de replicação de maneira separada dos demais códigos deste clone permite o reuso de código em 3 classes diferentes.

(9)

Este conjunto possui tamanho 203, TKS 26 e ocorre em 4 locais. Envolve basicamente dois métodos: um que retorna um objeto de uma classe baseado no id que recebe como parâmetro e um que retorna uma lista baseado num mapa de valores associados a atributos dessa classe que servem como restrição da consulta. O problema é que o tipo do objeto de retorno e o tipo do id da classe no primeiro método variam sutilmente entre as classes. Um exemplo de par com código redundante:

br.ufpe.cin.rgms.noticia.persistencia.DaoNoticia.java

public Noticia getNoticia(String texto) { Noticia retorno = null;

Criteria criteria = Persistence.getInstance().getSession().createCriteria(Noticia.class);

criteria.add(Restrictions.eq("texto", texto));

List<Noticia> lista = criteria.list();

if(lista.size() > 0){

retorno = lista.get(0); }

return retorno; }

public List<Noticia> getNoticias(HashMap<String, String> formfields) {

Criteria criteria = Persistence.getInstance().getSession().createCriteria(Noticia.class);

criteria.addOrder(Order.asc(this.getFirstAtributoDeOrdenacao())); criteria.addOrder(Order.asc(this.getSecondAtributoDeOrdenacao()));

for(String campo : formfields.keySet()){

String like = "%" + formfields.get(campo) + "%";

criteria.add(Restrictions.ilike(campo, like)); }

return criteria.list(); }

(10)

public LinhaPesquisa getLinhaPesquisa(int idLinha) { LinhaPesquisa retorno = null;

Criteria criteria =

Persistence.getInstance().getSession().createCriteria(LinhaPesquisa.class);

criteria.add(Restrictions.eq("id", idLinha));

List<LinhaPesquisa> lista = criteria.list();

if(lista.size() > 0){

retorno = lista.get(0); }

return retorno; }

public List<LinhaPesquisa> getLinhasPesquisa(HashMap<String, String> formfields) { Criteria criteria =

Persistence.getInstance().getSession().createCriteria(LinhaPesquisa.class);

criteria.addOrder(Order.asc(this.getFirstAtributoDeOrdenacao())); criteria.addOrder(Order.asc(this.getSecondAtributoDeOrdenacao()));

for(String campo : formfields.keySet()){

String like = "%" + formfields.get(campo) + "%";

criteria.add(Restrictions.ilike(campo, like)); }

return criteria.list(); }

Vale ressaltar que todas as classe envolvidas são subclasses de Dao e Dao é parametrizada no tipo do objeto envolvido. Uma solução seria colocar o código replicado no próprio supertipo Dao, apenas parametrizando os métodos com as diferenças entre as implementações das subclasses que o chamariam com os valores adequados.

(11)

Este conjunto possui tamanho 49, TKS 13 e ocorre em 2 lugares. Segue o código do par de classes envolvido:

br.ufpe.cin.rgms.noticia.persistencia.daoNoticia.java

public Noticia getNoticia(String texto) {

Persistence.getInstance().beginTransaction();

Noticia retorno = this.dao.getNoticia(texto);

Persistence.getInstance().commit();

return retorno; }

br.ufpe.cin.rgms.publicacao.persistencia.daoPublicacao.java

public Publicacao getPublicacao(int idPublicacao) { Persistence.getInstance().beginTransaction();

Publicacao retorno = this.dao.getPublicacao(idPublicacao);

Persistence.getInstance().commit();

return retorno; }

Este é outro exemplo que poderia ser solucionado com o refatoramento do código para a superclasse Controle, que é parametrizada no tipo do objeto e o Dao correspondente (que exatamente correspondem às diferenças entre os dois métodos).

Exemplo 4 – Conjunto 340 - 344

O clone aparentemente mais significativo no segundo gráfico, que é o clone das condições de if, como mencionado anteriormente, não representa um problema muito grande, pois fica muito restrito ao if, entretanto pode ser reduzido com a utilização de um método auxiliar que receberia uma String e retornaria se ela é válida. O conjunto de clone 344 é o de maior LEN (219).

br.ufpe.cin.rgms.membro.controle.ControleMembro

(12)

objeto.getSobrenome() == null || objeto.getSobrenome().equals("") || objeto.getTipo() == null || objeto.getTipo().equals("") ||

objeto.getDepartamento() == null || objeto.getDepartamento().equals("") || objeto.getUniversidade() == null || objeto.getUniversidade().equals("") || objeto.getTelefone() == null || objeto.getTelefone().equals("") ||

objeto.getEmail() == null || objeto.getEmail().equals("") ||

objeto.getWebsite() == null || objeto.getWebsite().equals("") || objeto.getCidade() == null || objeto.getCidade().equals("") || objeto.getPais() == null || objeto.getPais().equals("") || objeto.getSituacao() == null || objeto.getSituacao().equals("")) {

(13)

Métricas geradas pela ferramenta

Métricas geradas na primeira análise:

File Metrics

Nome Min. Max. Média

LEN 1 742 224.0 CLN 0 6 1.0 NBR 0 6 132.203 RSA 0 0,992 0.338226 RSI 0 0,367 0.0526634 CVR 0 0,992 0.366677 RNR 0,411 1 0.84829 ●

Clone-set Metrics

Name Min. Max. Average

LEN 52 215 968.182 POP 2 6 290.909 NIF 1 6 268.182 RAD 0 9 509.091 RNR 0,526 0,964 0.788263 TKS 12 27 174.545 LOOP 0 2 0.363636 COND 0 3 0.863636 McCabe 0 4 122.727

Métricas geradas na segunda análise:

File Metrics

Name Min. Max. Average

LEN 1 742 224.0 CLN 0 9 154.237 NBR 0 6 162.712 RSA 0 0,992 0.412152 RSI 0 0,681 0.11539 CVR 0 0,992 0.455962 RNR 0,411 1 0.84829

(14)

Clone-set Metrics

Name Min. Max. Average

LEN 40 219 941.795 POP 2 13 310.256 NIF 1 6 233.333 RAD 0 9 405.128 RNR 0,1 1 0.596243 TKS 10 27 145.641 LOOP 0 2 0.205128 COND 0 3 0.512821 McCabe 0 4 0.717949

Referências

Documentos relacionados

Assim, voto pelo acolhimento das preliminares defensivas, para anular o processo desde o interrogatório do acusado, inclusive, além de determinar, desde já, que o juízo

A espectrofotometria é uma técnica quantitativa e qualitativa, a qual se A espectrofotometria é uma técnica quantitativa e qualitativa, a qual se baseia no fato de que uma

Figura 8 – Isocurvas com valores da Iluminância média para o período da manhã na fachada sudoeste, a primeira para a simulação com brise horizontal e a segunda sem brise

b) desenvolver uma estratégia para implementação do JIT: a desenvolver uma estratégia para implementar o JIT assegura que a transição para ele seja mais suave e

Mova a alavanca de acionamento para frente para elevação e depois para traz para descida do garfo certificando se o mesmo encontrasse normal.. Depois desta inspeção, se não

6 Consideraremos que a narrativa de Lewis Carroll oscila ficcionalmente entre o maravilhoso e o fantástico, chegando mesmo a sugerir-se com aspectos do estranho,

Com o objetivo de compreender como se efetivou a participação das educadoras - Maria Zuíla e Silva Moraes; Minerva Diaz de Sá Barreto - na criação dos diversos

CAIXA, além do benefício previsto no parágrafo segundo da cláusula 26, o empregado que adotar ou obtiver guarda judicial para fins de adoção de criança fará jus