4.3 Implementação
6.5.5 Refatoração de um Laborious Repository Method
A Listagem6.9exibe parte do código da camada de modelo onde houve a ocorrência do problema de design Laborious Repository Method. Na linha 4 é exibido um método que realiza 4 chamadas (linhas 15, 24, 33 e 42) ao método execute da API de persistência do Django (django.db).
Listagem 6.9 – Ocorrência de Laborious Repository Method
1 # models.py 2 class Inscricao(models.ModelPlus): 3 4 def sub_instance(self): 5 if self.programa.tipo == Programa.TIPO_ALIMENTACAO: 6 try: 7 return InscricaoAlimentacao.objects.get(pk=self.pk) 8 except: 9 solicitacao_cafe = SolicitacaoAlimentacao.objects.create() 10 solicitacao_almoco = SolicitacaoAlimentacao.objects.create() 11 solicitacao_janta = SolicitacaoAlimentacao.objects.create() 12 cur = connection.cursor()
13 sql = "INSERT INTO ... values ({:d}, {:d}, {:d}, {:d})".format(
14 self.id, solicitacao_cafe.id, solicitacao_almoco.id, solicitacao_janta.id) 15 cur.execute(sql) 16 connection._commit() 17 return InscricaoAlimentacao.objects.get(pk=self.pk) 18 if self.programa.tipo == Programa.TIPO_TRABALHO: 19 try: 20 return InscricaoTrabalho.objects.get(pk=self.pk) 21 except: 22 cur = connection.cursor()
23 sql = "INSERT INTO ... values ({:d}, ’’, ’’)".format(self.id) 24 cur.execute(sql) 25 connection._commit() 26 return InscricaoTrabalho.objects.get(pk=self.pk) 27 if self.programa.tipo == Programa.TIPO_TRANSPORTE: 28 try: 29 return InscricaoPasseEstudantil.objects.get(pk=self.pk) 30 except: 31 cur = connection.cursor()
32 sql = "INSERT INTO ... alues ({:d}, ’’)".format(self.id) 33 cur.execute(sql)
Capítulo 6. Estudo de Caso 73 35 return InscricaoPasseEstudantil.objects.get(pk=self.pk) 36 if self.programa.tipo == Programa.TIPO_IDIOMA: 37 try: 38 return InscricaoIdioma.objects.get(pk=self.pk) 39 except: 40 cur = connection.cursor()
41 sql = "INSERT INTO ... values ({:d}, 1, 1)".format(self.id) 42 cur.execute(sql)
43 connection._commit()
44 return InscricaoIdioma.objects.get(pk=self.pk) 45 return None
A sugestão do catálogo para remoção do problema Laborious Repository Method é modificar o método dividindo-o em métodos menores, de modo que, cada um contenha apenas uma ação explícita de repositório. Para isso, identificamos os locais onde o método execute é chamado e extraímos esta parte do código para novos métodos. A Listagem 6.10
apresenta as alterações realizadas.
Listagem 6.10 – Ocorrência de Laborious Repository Method Refatorada
1 # models.py 2 class Inscricao(models.ModelPlus): 3 4 def sub_instance(self): 5 if self.programa.tipo == Programa.TIPO_ALIMENTACAO: 6 try: 7 return InscricaoAlimentacao.objects.get(pk=self.pk) 8 except: 9 self.create_InscricaoAlimentacao() 10 return InscricaoAlimentacao.objects.get(pk=self.pk) 11 if self.programa.tipo == Programa.TIPO_TRABALHO: 12 try: 13 return InscricaoTrabalho.objects.get(pk=self.pk) 14 except: 15 self.create_InscricaoTrabalho() 16 return InscricaoTrabalho.objects.get(pk=self.pk) 17 if self.programa.tipo == Programa.TIPO_TRANSPORTE: 18 try: 19 return InscricaoPasseEstudantil.objects.get(pk=self.pk) 20 except: 21 self.create_InscricaoPasseEstudantil() 22 return InscricaoPasseEstudantil.objects.get(pk=self.pk) 23 if self.programa.tipo == Programa.TIPO_IDIOMA: 24 try: 25 return InscricaoIdioma.objects.get(pk=self.pk) 26 except: 27 self.create_InscricaoIdioma() 28 return InscricaoIdioma.objects.get(pk=self.pk) 29 return None 30 31 def create_InscricaoAlimentacao(self): 32 solicitacao_cafe = SolicitacaoAlimentacao.objects.create() 33 solicitacao_almoco = SolicitacaoAlimentacao.objects.create() 34 solicitacao_janta = SolicitacaoAlimentacao.objects.create() 35 cur = connection.cursor()
36 sql = "INSERT INTO ... values ({:d}, {:d}, {:d}, {:d})".format(
37 self.id, solicitacao_cafe.id, solicitacao_almoco.id, solicitacao_janta.id) 38 cur.execute(sql)
Capítulo 6. Estudo de Caso 74
39 connection._commit() 40
41 def create_InscricaoTrabalho(self): 42 cur = connection.cursor()
43 sql = "INSERT INTO ... alues ({:d}, ’’, ’’)".format(self.id) 44 cur.execute(sql)
45 connection._commit() 46
47 def create_InscricaoPasseEstudantil(self): 48 cur = connection.cursor()
49 sql = "INSERT INTO ... values ({:d}, ’’)".format(self.id) 50 cur.execute(sql)
51 connection._commit() 52
53 def create_InscricaoIdioma(self): 54 cur = connection.cursor()
55 sql = "INSERT INTO ... values ({:d}, 1, 1)".format(self.id) 56 cur.execute(sql)
57 connection._commit()
Na linha 4 da Listagem 6.10, é apresentado o método sub_instance refatorado de modo que ele não executa mais nenhuma ação de repositório. Estas ações passaram a ser executadas nos métodos criados nas linhas 31, 41, 47 e 53 onde cada um executa apenas uma vez o método execute.
Após nova execução da MTVChecker as ocorrências dos problemas de design refatoradas não foram detectadas novamente. Portanto, apesar de genéricas, as sugestões de refatoração providas no catálogo foram suficientes para sanar os problemas detectados.
Ao analisarmos os códigos gerados a partir da refatoração percebemos que a resolução sistemática dos problemas de design catalogados podem contribuir para a redução do acomplamento entre camadas (Meddling View e Meddling Model), o aumento da coesão dos métodos (Meddling Model, Improper Use of Manager, Laborious Repository Method e Brain Repository Method), o aumento do reúso de código (Meddling View e Improper Use of Manager ), o encapsulamento de funcionalidades, antes espalhadas em diversas classes e funções (Meddling View e Improper Use of Manager ), além de reduzir a complexidade de métodos (Laborious Repository Method e Brain Repository Method).
75
7 Considerações Finais
Identificamos no estado da arte uma lacuna sobre a descrição de problemas de design que ocorrem em aplicações MTV. A partir da revisão da literatura construímos um catálogo de problemas de design que afetam aplicações que seguem o padrão arquitetural MTV. Os problemas deste catálogo foram inspirados em catálogos que apontam problemas comuns para o padrão arquitetural MVC – este possui regras similares ao do padrão arquitetural MTV – e também na experiência do autor com o desenvolvimento de aplicações MTV. Para validar o catálogo, realizamos questionários e entrevistas com especialistas no framework Django.
Além disso, implementamos uma ferramenta para automatizar a detecção dos problemas de design catalogados, pois consideramos que a leitura manual do código fonte em busca destes problemas é trabalhosa, complexa e passível de falhas. A ferramenta foi validada no contexto do SUAP, sistema com o qual o autor trabalha. Nele selecionamos duas apps e verificamos as ocorrências de falsos positivos e negativos.
Também realizamos estudo de caso no SUAP. Neste estudo, a MTVChecker identi- ficou 1.857 ocorrências de problemas de design. Diante da grande quantidade de problemas detectados selecionamos uma ocorrência de cada problema de design e a refatoramos seguindo a sugestão expressa no catálogo. As sugestões de refatoração apresentadas no catálogo se mostraram suficientes na remoção dos problemas de design. Ao analisarmos os códigos refatorados identificamos potenciais benefícios oriundos da remoção das ocorrências detectadas, por exemplo, redução do acomplamento, aumento da coesão, maior reúso de código, encapsulamento de funcionalidades e redução da complexidade de código.
Diante do exposto julgamos que o objetivo proposto, a saber: Apoiar a detecção de problemas de design que afetam negativamente atributos de qualidade de software em aplicações MTV, foi concluido com êxito tendo em vista a elaboração de um catálogo que conceitua problemas de design específicos de aplicações MTV e a implementação da ferramenta MTVChecker que automatiza a detecção destes problemas.