• Nenhum resultado encontrado

4.3 Implementação

4.3.5 Laborious Repository Method

Um Laborious Repository Method é detectado quando algum método realiza mais de uma chamada a métodos de persistência. Abaixo são apresentados os passos executados pelo algortimo de detecção deste problema de design.

1. Procure por chamadas executadas dentro de métodos.

2. Verifique se a chamada parte de uma instância de Manager e se o método chamado tem o nome raw.

3. Verifique se a chamada parte de uma instância de django.db.connection e se o método chamado tem o nome execute.

4. Adicione uma detecção de Laborious Repository Method se as condições do passo 1 ou 2 ocorrerem 2 vezes ou mais no mesmo método.

A Listagem4.6 exibe a implementação do algoritmo apresentado acima. Listagem 4.6 – Implementação da Classe LaboriousRepositoryMethodVisitor

1 class LaboriousRepositoryMethodVisitor(Checker): 2

3 def __init__(self, module, models):

4 self.smell = "Laborious Repository Method"

5 self.count = 0

6 self.is_assign = False 7 self.querys = [] 8 self.cursor = None

9 Checker.__init__(self, module, models) 10

11 def visit_Call(self, node): 12 if self.method: 13 name = self.visit_Attribute(node.func) 14 split = name.split(’.’) 15 if len(split) > 1: 16 cls = split[0] 17 method = split[1]

18 method_2 = len(split) > 2 and split[2] or None

Capítulo 4. MTVChecker 51

20 self.is_manager_raw(cls, method, method_2)): 21 self.count+=1

22 else:

23 self.generic_visit(node) 24

25 def is_manager_raw(self, cls, method, method_2): 26 if ’raw’ == method_2 and self.imports.has_key(cls): 27 split = self.imports[cls].split(’.’)

28 key = ’{}.{}.{}’.format(split[0], split[1], cls) 29 if self.models.has_key(key):

30 managers = self.models[key][0][’managers’] 31 for manager in managers:

32 return manager == method 33 return False

34

35 def is_api_persistence(self, cls, method): 36 if self.is_assign:

37 if self.imports.has_key(cls): 38 package = self.imports[cls]

39 if ’django.db.connection’ == package and ’cursor’ == method: 40 self.cursor = True

41 return False

42 elif self.cursor and self.cursor == cls and ’execute’ == method: 43 return True

44 else:

45 return False 46

47 def pos_visit_FuncitonDef(self, node): 48 if self.count > 1:

49 self.add_violation(node) 50 self.count = 0

51 self.querys = []

Na Listagem 4.6 é apresentada a classe LaboriousRepositoryMethodVisitor que implementa este algoritmo. Ela recebe como entrada nós de qualquer camada e uma lista contendo todas as classes de modelo da aplicação e os managers associados a elas. O método visit_Call na linha 11 implementa o passo 1 descrito no algoritmo. Ele captura todas as chamadas que ocorrem dentro de um método. Na linha 25 o método visit_api_persistence implementa o passo 2. A lista de classes de modelo é utilizada neste método para identificar instâncias de managers. Na linha 35 o método is_api_persistence implementa o passo 3. Na linha 47 o método pos_visit_FuncitonDef, após analisar o método por completo, adiciona ou não a detecção no problema de design (passo 4).

4.4

Validação

O processo de validação da MTVChecker foi realizada da seguinte forma: a) Escolha do sistema e definição da versão do código fonte analisado; b) Identificação dos problemas de design através da análise manual do código fonte; c) Aplicação da MTVChecker no código analisado; e d) Comparação dos resultados obtidos pela ferramenta e pela análise manual.

Capítulo 4. MTVChecker 52

Em razão do conhecimento que o autor detém sobre o código do SUAP, este sistema foi escolhido para validação da ferramenta. Foi gerado localmente uma versão deste sistema que remete ao código fonte datado de 30 de Junho de 2018. Por conta do tamanho da aplicação foi selecionado um conjunto menor de dados para análise manual e da ferramenta. Com base no conhecimento prático do autor no desenvolvimento e manutenção do SUAP as apps “gestão” e “comum” foram analisadas.

A app “gestão” foi selecionada por conter em sua implementação diversos métodos com estruturas de SQL, o que pode gerar uma boa amostragem na análise dos problemas de design relacionados com SQL. A app “comum”, que implementa funcionalidades utilizadas pelas demais apps, foi escolhida devido sua relevância no SUAP e também por não possuir uma quantidade excessiva de linhas, o que dificultaria sua análise manual. A Tabela 5

exibe o tamanho do módulos em quantidade de linhas de código. Tabela 5 – Tamanho dos Módulos Selecionados

App Módulo LOC

comum models 1.686

comum views 1.530

gestão models 1.785

gestão views 708

Conforme visto na Tabela 5foram selecionados os módulos models e views de cada app. Os arquivos correspondentes destes módulos são models.py e views.py da app “gestão” e models.py e views.py da app “comum”. O conteúdo destes arquivos possui aproxidamente de 6 mil linhas de código. A análise manual do código fonte foi realizada de modo que cada arquivo fosse estudado com foco apenas em encontrar um tipo de problema de design por vez.

4.4.1

Resultados

O objetivo desta validação é checar se as ocorrências de problemas que a MTV- Checker indica estão condizentes com as estratégias de detecção apresentadas no catálogo

do capítulo anterior. Portanto, neste momento ainda não serão avaliados os problemas detectados no sistema alvo, mas se os algoritmos da ferramenta realizam a checagem das estruturas de código da forma esperada. Para isso, utilizamos thresholds baixos com intenção de que a ferramenta crie mais alertas e, com isso, gerando mais oportunidades de avaliar até que ponto o que é identificado é condizente com o algoritmo de detecção. A avaliação dos problemas de um sistema alvo, com uma estratégia mais elaborada de definição dos thresholds, será apresentada no próximo capítulo.

Os thresholds para as complexidades média e alta da estrutura de SQL foram 2 e 3 respectivamente. Estes mesmos valores foram aplicados aos thresholds da complexidade

Capítulo 4. MTVChecker 53

estrutural do código. Desse modo, esperamos coletar uma boa amostragem de problemas de Brain Repository Method. A Tabela 6 mostra o quantitativo de problemas de design detectados após análise manual dos arquivos selecionados.

Tabela 6 – Problemas de Design Detectados Manualmente

comum gestão

models.py views.py models.py views.py

Meddling View 0 66 0 0

Meddling Model 36 0 0 0

Improper Use of Manager 6 0 50 0

Brain Repository Method 0 0 15 0

Laborious Repository Method 0 1 0 0 De acordo com o apresentado na Tabela6, encontramos 66 problemas de Meddling View, 36 problemas de Meddling Model, 56 problemas de Improper Use of Manager, 15 problemas de Brain Repository Method e apenas 1 problema de Laborious Repository Method.

Para identificar os problemas de Meddling View procuramos pelo uso de alguma função ou classe importada do pacote django.db.*. Para identificar os problemas de Meddling Model procuramos por strings que contivessem algum caracter “<” ou “/>” e avaliamos se era parte de um HTML. Para identificar os problemas de Improper Use of Manager procuramos em cada classe por importações de outras classes e verificamos se alguma classe importada não era relacionamento da classe analisada e se acessava algum manager. Para identificar os problemas de Brain Repository Method procuramos por strings com texto SQL e calculamos manualmente a fórmula de dificuldade de Halstead. Para identificar os problemas de Laborious Repository Method procuramos no código pelas palavras “raw” e “execute”.

A Tabela 7 apresenta o quantitativo dos problemas de design detectados pela MTVChecker.

Tabela 7 – Problemas de Design Detectados Automaticamente

comum gestão

models.py views.py models.py views.py

Meddling View 0 66 0 0

Meddling Model 36 0 0 0

Improper Use of Manager 6 0 49 0

Brain Repository Method 0 0 13 0

Laborious Repository Method 0 1 0 0 De acordo com o apresentado na Tabela7 a checagem automática encontrou 66 problemas de Meddling View, 36 problemas de Meddling Model, 55 problemas de Improper

Capítulo 4. MTVChecker 54

Use of Manager, 13 problemas de Brain Repository Method e apenas 1 problema de Laborious Repository Method.

Para identificar a presença de falsos negativos ou falsos positivos comparamos o conjunto de problemas de design detectado pela ferramenta com o conjunto de problemas detectados manualmente. Consideramos um falso positivo a detecção de um problema pela ferramenta, mas que na análise manual não foi considerado como problema de design. Consideramos um falso negativo a detecção de algum problema de design na análise manual, mas que não foi detectada pela MTVChecker. A Tabela 8exibe o resultado desta análise.

Tabela 8 – Contagem de Falsos Positivos e Negativos

Verdadeiro Positivo Falso Positivo Falso Negativo Meddling View 66 0 0 Meddling Model 36 0 0

Improper Use of Manager 55 0 1

Brain Repository Method 13 0 2

Laborious Repository Method 1 0 0

Conforme apresentado na Tabela8 não houve casos de falso positivo, no entanto, o problema Improper Use of Manager apresentou 1 falso negativo e o problema Brain Repository Method apresentou 2 falsos negativos. Todos os falsos negativos foram analisados em busca dos motivos que causaram a não detecção pela ferramenta. A Listagem 4.7

apresenta os 3 casos de falsos negativos.

Listagem 4.7 – Falsos Negativos

1 def get_filtro_emit_ug(self, uo, incluir_fav=False): 2 codigos = ’’

3 if uo:

4 for ug in UnidadeGestora.objects.filter(uo=uo): 5 if not codigos:

6 codigos = ug.pk

7 else:

8 codigos = ’{}, {}’.format(codigos, ug.pk) 9 if codigos:

10 if incluir_fav: # emit_ug = 4587 and

11 return ’ and (emit_ug in ({}) or (fav_ug in ({})))’.format(codigos, codigos) 12 return ’ and emit_ug in ({})’.format(codigos)

13 if uo:

14 return ’ and emit_ug in (-1)’

15 return codigos 16

17 def get_qs_renda_familiar(self, limite_inferior=0, limite_superior=1000, uo=None): 18 qs_rfp = self.get_qs_alunos_matriculados(uo=uo)[0]

19 qs_rfp =

qs_rfp.filter(aluno__historicorendafamiliar__numero_salarios__gte=Decimal(str(limite_inferior)), 20 aluno__historicorendafamiliar__numero_salarios__lt=Decimal(

21 str(limite_superior))).order_by(’aluno__pessoa_fisica__nome’) 22

Capítulo 4. MTVChecker 55

23 filtro_data_limite_historico_familiar = ’ AND "data" between \’{}\’ and \’{}\’ ’.format( 24 get_data_base().strftime(’%Y-%m-%d’),

25 get_data_limite().strftime(’%Y-%m-%d’)) 26 qs_rfp = qs_rfp.extra(where=[

27 ’"ae_historicorendafamiliar"."id" = (SELECT "id" from "ae_historicorendafamiliar" WHERE "aluno_id" = "edu_aluno"."id" {} ORDER BY "id" DESC LIMIT 1)’.

28 format(filtro_data_limite_historico_familiar)]) 29 return qs_rfp

30

31 def get_qs_alunos_ingressantes_turmas_concluintes(self, uo=None): 32 from comum.models import Ano

33 qs = Aluno.objects.filter(ano_let_prev_conclusao=get_ano_referencia(), 34 curso_campus__modalidade__id__isnull=False) | \ 35 Aluno.objects.filter(curso_campus__descricao__icontains=’PROITEC’, 36 ano_letivo=Ano.objects.get(ano=get_ano_referencia())) 37 qs = qs.distinct()

38 if uo: qs = qs.filter(curso_campus__diretoria__setor__uo=uo) 39 return [qs]

Os métodos apresentados na Listagem 4.7 são exemplos de falsos negativos. O primeiro e segundo são falsos negativos de Brain Repository Method e o terceiro, de Improper Use of Manager. No método get_filtro_emit_ug (linha 1) a ferramenta considerou que não existem estruturas de SQL. Isso ocorreu porque ela não avaliou as strings nas cláusulas de retorno do método (linhas 11, 12 e 14). Apesar da complexidade estrutural do SQL em cada retorno isolado ser baixa nesse exemplo, a ferramenta não pode ignorar a avaliação destas strings. Essa limitação deve ser corrigida na próxima versão da MTVChecker.

No método get_qs_renda_familiar (linha 17) a ferramenta não identificou outra string SQL na linha 27 e avaliou a complexidade estrutural do SQL apenas da string da linha 23 obtendo uma baixa complexidade. O algoritmo de identificação de SQL é essencial na detecção dos problemas Brain Repository Method e Meddling View. Reconhecemos que a limitação deste algoritmo pode comprometer a taxa de detecção da ferramenta, mas até o momento não dispomos de uma solução definitiva.

No método get_qs_alunos_ingressantes_turmas_concluintes (linha 31) a ferra- menta não identificou o uso do Manager objects da classe Ano na linhas 36. Essa limitação ocorreu pelo fato deste manager ser acionado dentro da implementação dos filtros do manager da classe Aluno (linha 35). Nossa ferramenta não analisa o conteúdo dos filtros de um manager, no entanto, será avaliado em futuras atualizações da MTVChecker a implementação da análise interna dos filtros aplicados na chamada dos managers.

Em posse dos dados apresentados na Tabela8 calculamos as métricas precision, recall e F-measure da MTVChecker. A métrica precision indica quantos itens selecionados são relevantes, isto é, quão útil é o resultado da pesquisa. A métrica recall indica quantos itens relevantes são selecionados, isto é, quão completo são os resultados apresentados. Os valores destas métrica variam de 0 a 1. Uma precision alta indica que o algoritmo retornou resultados substancialmente mais relevantes do que irrelevantes. Um recall alto indica que o algoritmo retornou a maioria dos resultados relevantes. F-measure é uma métrica que

Capítulo 4. MTVChecker 56

harmoniza os valores obitidos pelas duas métricas anteriores. Abaixo são apresentadas as fórmulas de cálculo destas métricas.

Precision = Verdadeiro Positivo/(Verdadeiro Positivo + Falso Positivo) Recall = Verdadeiro Positivo/(Verdadeiro Positivo + Falso Negativo) F-measure = 2 x (Precision x Recall)/(Precision + Recall)

A Tabela9 apresenta o resultados das métricas precision, recall e F-measure. Tabela 9 – Métricas Precision, Recall e F-measure

Precision Recall F-measure

Meddling View 1 1 1

Meddling Model 1 1 1

Improper Use of Manager 1 0,98 0,98

Brain Repository Method 1 0,86 0,92

Laborious Repository Method 1 1 1

Geral 1 0,98 0,98

Conforme visto na Tabela 9, a MTVChecker demonstrou ser capaz de detectar somente resultados relevantes apresentando precision igual a 1. Também expôs um excelente resultado para a taxa de recall apresentado o valor 0,98 indicando que a ferramenta consegue detectar maior parte dos resultados relevantes.

4.4.2

Ameaças à Validade

Diversidade de Código. A base de código selecionada para validação da fer-

ramenta pode não cobrir todas as possibilidades de como os problemas de design são codificados. No entanto, consideramos que, a partir dos resultados obtidos, identificamos as limitações e validamos todas as estratégias de detecção implementadas na ferramenta.

Um Analista Envolvido. A análise de código realizada por pessoas pode ser falha

e resultar na não percepção de algum problema existente. Apesar de apenas o autor desta dissertação ter analisado manualmente o código alvo desta validação, mas considerando o seu conhecimento prévio dos detalhes de implementação do SUAP e que foi realizada uma análise minuciosa de cada parte do código, acreditamos que todos os problemas de design existentes foram identificados.

57

5 Trabalhos Relacionados

Neste capítulo apresentamos trabalhos que identificam estruturas de código proble- máticas que serviram de base para a construção do catálogo de problemas de design em aplicações MTV e também trabalhos que realizam a análise estática de código fonte.

Fowler (1999) foi o primeiro a usar o termo bad smell para se referir a fragmentos de código que podem conter algum problema. Ele apresentou um catálogo composto por 22 bad smells que podem afetar qualquer tipo de sistema, independentemente da arquitetura adotada. Estratégias de detecção e refatoração são exploradas a fim de eliminar estes problemas. Nosso catálogo também descreve alguns problemas de design que se parecem com os bad smells de Fowler (1999) no sentido de indicar algo que “cheira mal” mesmo que não viole nenhuma regra.

Lippert e Roock (2006) definem o conceito de architectural smell. Para eles é uma indicação de um problema oculto que ocorre em um nível mais alto de abstração de um sistema. Architectural smells podem ocorrer nas relações de uso e herança entre classes, dentro e entre pacotes, dentro e entre subsistemas e dentro e entre camadas. Suas causas incluem, entre outras coisas, aplicar uma solução de design em um contexto inadequado, misturar combinações de abstrações de design ou aplicar abstrações de design no nível errado de granularidade. Estes problemas são parecidos com os problemas de design Meddling View e Meddling Model do nosso catálogo que indicam a quebra de regras arquiteturais.

Aniche et al.(2017) apresentam um catálogo de code smells que se manifestam em sistemas construídos sob o padrão arquitetural MVC. A escolha do MVC foi motivada pelo fato deste padrão ser utilizado por muitos frameworks populares, tais como Ruby on Rails, Spring MVC, e ASP.NET MVC. Após pesquisa e entrevista com desenvolvedores de software sobre boas e más práticas no uso do padrão arquitetural MVC foi proposto um catálogo formado por 6 code smells.

O catálogo proposto por Aniche et al. (2017) compreende problemas de design encontrados nas camadas Model (Meddling Service, Brain Repository, Laborious Repository Method e Fat Repository) e Controller (Promiscuous Controller e Brain Controller ). Abaixo detalhamos os problemas relacionados à camada Model. Os problemas da camada Controller não foram aplicados nesta dissertação, pois no padrão arquitetural MTV, esta

camada está implicita para o desenvolvedor.

Meddling Service é descrito como um serviço que consulta diretamente o banco de dados. Serviços são implementados quando existe a necessidade de oferecer uma operação independente no modelo, sem estado encapsulado. Eles devem conter regras de negócios

Capítulo 5. Trabalhos Relacionados 58

e/ou controlar lógica de negócio complicada entre diferentes classes de domínio. O uso de consultas SQL ou dependência a APIs de persistência em um serviço é considerado uma má prática e deve ser evitado. A estratégia abordada para detectar este problema consiste em verificar se existe um serviço que contenha uma dependência para qualquer API de persistência (por exemplo, JDBC, Hibernate, JPA e iBatis) e faça uso dela uma ou mais vezes.

Brain Repository é descrito como um repositório que contém lógica complexa. Repositórios, que são responsáveis por encapsular a lógica de persistência, comumente lidam com linguagens de consulta, por exemplo, SQL ou JPQL. No entanto, um indicativo de problema na implementação de um repositório ocorre quando ele apresenta consultas complexas, por exemplo, com vários joins ou filtros complexos, e também lógica complexa para montagen destas consultas. A estratégia abordada para detectar este problema consiste em calcular a complexidade da consulta SQL, a complexidade ciclomática do método e verificar se elas superam os thresholds estabelecidos.

Laborious Repository Method é descrito como um método de repositório com várias ações de banco de dados. É uma boa prática um método ter apenas uma responsabilidade e fazer somente coisa. Analogamente, se um método contiver mais de uma consulta SQL ou realizar mais de uma ação no banco de dados, pode ser considerado muito complexo ou pouco coeso. A estratégia abordada para detectar este problema consiste em identificar ações de banco de dados, por exemplo, o uso de métodos query do Spring Data, createQuery ou createSqlQuery do Hibernate, e se estes métodos são invocados 2 vezes ou mais dentro do mesmo método.

Fat Repository é descrito como um repositório que gerencia muitas entidades. Uma classe de repositório deve gerenciar apenas uma entidade. Se um repositório lida com muitas entidades de uma só vez, isso pode implicar na baixa coesão e dificultar a manutenção. A estratégia abordada para detectar este problema consiste em contar o número de dependências no repositório que são classes de entidade e verificar se o resultado é maior que o threshold definido.

Projetos utilizando o Spring MVC foram analisados para validar este catálogo. Também foi realizado um estudo com especialistas em outros frameworks MVC (VRaptor, Ruby on Rails, Asp.Net MVC e Play! ) para verificar se os problemas sugeridos por eles são genéricos o suficiente para serem aplicados em diferentes frameworks deste padrão. De acordo com os especialistas consultados, maior parte dos code smells são aplicáveis em seus frameworks, no entanto, em alguns casos, foi necessário adaptar alguma regra ou estratégia de detecção.

Velasco-Elizondo et al.(2017) definem um conjunto de architectural smells relevantes no padrão arquitetural MVC. Estes smells foram validados no contexto de aplicações desenvolvidas com o framework Yii – framework MVC na linguagem PHP. Para detectá-los

Capítulo 5. Trabalhos Relacionados 59

de forma automática propuseram um ferramenta de análise estática.

O catálogo de Velasco-Elizondo et al. (2017) consiste em detectar os seguintes problemas de design na camada Model: elementos que incluem processamento ou dados da camada de visão, isto é, elementos do modelo que lidam com regras de apresentação, por exemplo, a presença de código HTML; e elementos que incluem processamento de dados da camada de controle, isto é, elementos do modelo que têm acesso direto a variáveis de requisições de usuário, por exemplo, variáveis POST e GET de uma requisição HTTP.

Na camada View são detectados os seguintes problemas: elementos que incluem processamento ou dados da camada de modelo, isto é, elementos da visão que lidam com lógica de domínio, por exemplo, código de consulta a banco de dados; e elementos que incluem processamento ou dados da camada de controle, isto é, elementos da camada de visão que tem acesso direto a variáveis de requisições de usuário, por exemplo, variáveis POST e GET de uma requisição HTTP.

Na camada Controller são detectados os seguintes problemas: elementos que incluem processamento ou dados da camada de visão, isto é, elementos do controle que lidam com lógica de apresentação, por exemplo, código HTML; e elementos que incluem processamento ou dados da camada de modelo, isto é, elementos da camada de controle que tem lógica de domínio, por exemplo, código de consulta a banco de dados.

Apesar do catálogo de Velasco-Elizondo et al. (2017) cobrir problemas de design nas 3 camadas do padrão arquitetural MVC, a reutilização deste catálogo, assim como, de sua ferramenta em frameworks MVCs de outras linguagens de programação é limitada, pois depende de adaptações nas regras de detecção e sua ferramenta é capaz de detectar smells apenas em sistemas implementados na linguagem PHP.

Os problemas de design do nosso trabalho foram inspirados nas definições dos catálogos levantadas porAniche et al. (2017) eVelasco-Elizondo et al.(2017). A Tabela 10

apresenta um comparativo do catálogo de problemas de design do MTV com os catálogos

Documentos relacionados