APLICAÇÃO DE PADRÕES DE PROJETO NA REFATORAÇÃO DE CÓDIGO DE UM SISTEMA DE MONITORAMENTO REMOTO DE UMA REDE LOCAL.

Artigo apresentado à Pró-Reitoria de Pesquisa e Pós-graduação da Universidade do Sagrado Coração, como parte dos requisitos para obtenção do título de especialista em Desenvolvimento de Software para Web - DSW, sob orientação do Prof. Me. Anderson Pazin.

UNIVERSIDADE DO SAGRADO CORAÇÃO

Autor: DIEGO PREVIERO


RESUMO


A refatoração proporciona a uma melhoria a um código legado, com uso de técnicas adequadas, uma série de benefícios, desde facilidade na sua leitura à um aumento de sua capacidade de escalabilidade. A proposta deste trabalho é aplicar a refatoração a um software legado, desenvolvido com a linguagem Java e que está em uso desde 2013. Para apoiar esse processo aplicou-se padrões de projeto, mais especificamente o padrão Adapter, onde algumas classes deram lugar a implementação de Interfaces e o uso de troca de mensagens utilizando strings foi substituído pelo envio de objetos específicos através de conexões via socket, o que agora proporciona a possibilidade de expansão do projeto por permitir total reuso do código implementado.


Palavras-chave: Refatoração. Padrões. Adapter. Interface. Java.


1. INTRODUÇÃO

A refatoração de código é uma prática muito importante durante o processo de desenvolvimento, ela visa uma reestruturação do código, porém sem que se altere sua aparência ou funcionalidades. Essa reestruturação se dá através da decomposição de métodos e classes e uso de polimorfismo simplificando tarefas, principalmente quando se percebe que o projeto está crescendo, tornando o código mais fácil de se entender permitindo adicionar ou remover funcionalidades sem comprometer o código existente e evitar problemas como código duplicado.(FOWLER,2012).

A aplicação de padrões de projeto à remodelagem da estrutura do código ajuda na simplificação do código pois consiste de técnicas para solução de problemas já conhecidos pelos desenvolvedores e somada a aplicação de orientação a objetos permite uma maior flexibilidade e reuso dos dados. (ECKEL,2017).

Este trabalho tem por objetivo aplicar padrões de projetos na refatoração de um sistema legado, possibilitando o aprimoramento do código e permitindo assim o seu melhor entendimento. As técnicas aplicadas nesse projeto podem ser um referencial para projetos futuros.


2. FUNDAMENTAÇÃO TEÓRICA

Nesta seção, serão abordados os assuntos referentes aos conhecimentos necessários para o desenvolvimento do projeto.


2.1 – Orientação Objeto

Um desenvolvimento baseado em orientação a objetos proporciona uma base sólida ao código ao abstrair um problema grande reduzindo o mesmo em vários pequenos problemas mais simples e facilitar a manutenção.O objetivo deste paradigma é a representação de forma mais clara do mundo real através de estruturas que sejam as mais semelhantes possíveis.

Na programação orientada a objetos são definidos novos tipos através da criação de classes, e esses tipos podem ser instanciados criando objetos. A ideia é que um objeto represente uma entidade concreta enquanto sua classe representa uma abstração dos seus conceitos. (GUERRA,2017).

O conceito principal da orientação a objetos, a classe, tem o objetivo de combinar em uma única entidade todos os dados, chamados atributos, e procedimentos, conhecidos como métodos, que se referem a este ente do mundo real. A correta definição de seus dados, que representam o estado corrente do objeto, e seus métodos, que são as ações que o mesmo pode executar.

Definem-se as classes e, a partir deste molde, criam-se instâncias das mesmas, denominadas como objetos. Os Objetos são instâncias de classes, representam a materialização das mesmas. Para que uma classe possa efetivamente ser utilizada, é necessário que instâncias da mesma sejam criadas.


2.2 – Interface

Em uma interface todos os métodos são públicos e abstratos e não têm a necessidade de explicitar tais características, pois seria redundante. Esses métodos são declarados, mas não possuem implementação, somente demonstram a intenção do que serão capazes de fazer, eles serão implementados nas classes que fizerem uso dessa interface.

Segundo Niemeyer (2013), uma interface é uma expansão conceitual de métodos abstratos, pois, oferece um contrato para o desenvolvedor e o compilador, onde descreve que os métodos abstratos oferecidos pela interface devem ser codificados em todas as classes que implementam essa interface, caso contrário um erro de compilação será exibido. Dessa forma uma interface funciona como um tipo de objeto. Uma classe pode implementar várias interfaces permitindo uma espécie de herança múltipla na linguagem JAVA.


2.3 – Sockets

Os sockets TCP/IP (TransmissionControlProtocol / Internet Protocol) permite que sistemas se comuniquem dentro de uma rede, podendo enviar ou receber informações. Neste tipo de comunicação uma conexão fica ativa, tanto no cliente quando no servidor, para que seja possível realizar estas trocar de informações.

Segundo JAQUES (2007) sockets TCP/IP, são usados para implementar conexões confiáveis, bidirecionais e ponto a ponto, com base em um stream entre computadores. Os sockets podem ser usados para conectar o sistema de E/S de um programa Java a outros programas em outras máquinas na Internet.


2.4- Padrões de Projetos

Um Padrão de Projeto trata de técnicas de modelagem reutilizável para um problema comum no desenvolvimento de sistemas de software, não são códigos prontos ou soluções específicas, e sim um modelo de como resolver os problemas, sendo soluções que já foram utilizadas e testadas, assim tornando uma grande ferramenta com grande eficácia.

Além disso, um bom Design Pattern é importante para manutenibilidade, após o desenvolvimento, a equipe de suporte precisa estar ciente do que foi desenvolvido, pois se necessário fazer alguma alteração ou expansão do software no futuro, essa manutenção pode ser efetuada de forma mais tranquila.

Segundo o livro "Design Patterns: Elements of Reusable Object - Oriented Software", escrito por Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides (GAMA et. Al,1995), são descritos 23 padrões de projetos subdivididos em 3 grupos:


a) “Criação: onde tratam da construção do objeto, eles ajudam a tornar um sistema independente de como seus objetos são criados, compostos e representados;

b) Estrutural: que tratam da relação entre classes e objetos e como são compostos para formar estruturas complexas;

c) Comportamental: tratam da comunicação entre os objetos e suas responsabilidades de atribuição de algoritmos; ”’


2.4.1 – Padrão de Projeto: Adapter

Uma vantagem do uso do padrão Adapter é a reutilização de código pois permite ao desenvolvedor fazer reuso de uma classe existente, podendo adaptar-se ao contexto em que a mesma deve ser aplicada. Deve ser utilizado quando mais de uma classe possui um objetivo final em comum, entretanto os seus métodos possuem peculiaridades em relação as demais, seus métodos podem ter outras dependências ou serem executadas de maneira diferente.

De acordo com Gamma et. al.,(1995) o padrão Adapter funciona como um conversor permitindo que uma classe que receba como parâmetro uma interface de um tipo possa receber uma interface de um tipo diferente e ainda assim seja compatível.


Usar o padrão Adapter quando:

[..]. “Você quer usar uma classe existente e sua interface não é compatível com a que você precisa.

Você quer criar uma classe reutilizável que coopera com classe não relacionadas ou não previstas, ou seja, classes que não necessariamente têm interfaces compatíveis.

(Somente adaptador de objeto) você precisa utilizar diversas subclasses existentes, mas é impraticável adaptar suas interfaces criando subclasses para cada uma. Um adaptador de objeto pode adaptar a interface de sua classe pai. (GAMMA,1995, p136)”.


3. METODOLOGIA

O código fonte a ser refatorado pertence a um sistema chamado LabManager que foi desenvolvido com a finalidade de melhorar o gerenciamento de redes no ambiente escolar, automatizando tarefas através da possibilidade de execução remota de comandos em uma ou diversas máquinas.

Sua principal aplicação é oferecer ao utilizador, de forma intuitiva, funcionalidades que normalmente necessitariam um conhecimento avançado para serem executadas e executá-las ao mesmo tempo em todos os computadores conectados à rede. Este possui uma estrutura de cliente-servidor onde o servidor determina os comandos que serão executados e os envia para a máquina cliente que recebe, trata as informações e executa a tarefa.

O sistema foi utilizado nos laboratórios de informática de duas escolas de ensino fundamental no município de Vera Cruz estado de São Paulo, cada escola com dezoito computadores.

O sistema foi desenvolvido com o intuito de automatizar as tarefas mais comuns de uso do laboratório a fim de promover um maior aproveitamento do tempo de aula, onde cada turma tem cinquenta minutos de aula. Atividades onde todos os computadores devem abrir um site específico, abrir um arquivo específico ou acessar um diretório no computador para só então resolver um exercício são exemplos de tarefas que demandam um tempo valioso e que com o uso do software LabManager são realizadas instantaneamente permitindo ao aluno dedicar esse tempo exclusivamente a realização dos exercícios.

O Quadro 1 apresenta algumas das funcionalidades implementadas no software LabManager e que garantem essas facilidades na execução das tarefas.

A funcionalidade de índice 1 executa o método RodarApp(comando), que é responsável por executar comandos nativos da plataforma Windows no prompt de comando através da biblioteca Runtime. O parâmetro “comando” é passado para o método getRuntime().exec(comando) que é executado em segundo plano.

No índice 2 temos o método Msg(comando) que exibe na tela da máquina cliente uma janela com uma mensagem. Essa mensagem é passada pelo parâmetro “comando” para o método showMessageDialog(null,comando) da biblioteca JOptionPane.

O método de índice 3 AtivaCaps (comando) é responsável por ativar ou desativar a tecla CapsLock da máquina cliente através de um valor booleano passado pelo parâmetro “comando”para o método setLockingKeyState(KeyEvent.VK_CAPS_LOCK, comando) da biblioteca Toolkit.

O índice de número 4 aponta para o método Web (comando), o qual identifica qual o navegador definido como padrão na máquina cliente e abre um site especificado no parâmetro “comando”, isso é feito através da biblioteca Desktop invocando o método browse(new URI(comando)).


Quadro 1 Algumas Funcionalidades do Sistema

Index

Assinatura da Classe

Funcionalidade

1

RodarApp(comando)

Executar um aplicativo

2

Msg(comando)

Exibir uma mensagem

3

AtivarCaps(comando)

Ativar ou desativar o CapsLock do teclado

4

Web(comando)

Abrir um site específico

Fonte: Elaborada pelo autor.


Para que aconteça a comunicação entre o computador Servidor e as máquinas Cliente, é feita uma conexão via Socket que permite a troca de informações através do protocolo TCP/IP. Duas mensagens de texto são enviadas do servidor para o cliente, uma chamada index, contendo um valor de índice e outra chamada comando, contendo a instrução a ser executada pela funcionalidade referenciada pelo índice. O índice representa uma das tarefas mencionadas na listagem acima.

Pelo fato de, ambos os módulos cliente e servidor, terem sido desenvolvidos sem se ater à boas práticas de programação, toda e qualquer alteração que se propusesse ser feita tornava-se extremamente laboriosa, pois, para que o módulo cliente entenda as instruções que o módulo servidor envia, é necessário que haja consonância entre a codificação de ambos, para alterar comandos existentes ou incluir novos no módulo servidor, teria também que modificar o módulo cliente para que este pudesse saber o que deve ser feito com a instrução recebida.

Os métodos implementados eram muitos extensos e mal estruturados, muitas vezes dependiam de vários outros métodos em forma de cascata, dificultando a leitura e manutenção do código e atuado como fator limitante para a ampliação do projeto.

As alterações propostas visam alcançar benefícios como a reutilização de código através do uso de interfaces e orientação a objetos evitando assim reescrita. Portanto, utilizando o padrão de projeto adapter, obteve-se melhor legibilidade e escalabilidade do projeto, permitindo-se assim que o mesmo evolua sem influenciar no código primário, pois, quaisquer alterações poderiam comprometer ou corromper o funcionamento da codificação existente.


4. RESULTADOS E DISCUSSÃO

No projeto inicial a estrutura do comando não foi pensada respeitando a orientação a objetos, sendo constituído por duas strings as quais representavam um índice e o comando em si que seria executado. As duas strings são enviadas através de uma conexão via socket para o cliente que por sua vez efetua a leitura, submetendo-as a uma estrutura condicional, switch/case para determinar qual classe será instanciada recebendo como parâmetro a ação a ser executada, como é mostrado na Figura 1.


Figura 1 Switch/Case


Fonte: Elaborada pelo autor.


No projeto refatorado foi criada a interface Comando que possui o método público executaComando(), como pode ser visto na Figura 2, que serve de contrato para as classes que irão implementar essa interface.


Figura 2 - Interface


Fonte: Elaborada pelo autor.


Também foi criada a classe ComandoAdapter que implementa a interface Comando, como é visto na linha 7 e seu método executaComando(), mostrado na linha 17, utilizando o padrão de projeto Adapter. A Figura 3 demonstra sua implementação.


Figura 3 - Classe Adapter


Fonte: Elaborada pelo autor.


Na comunicação via socket as duas strings, na aplicação servidor, foram substituídas pela classe ComandoAdapter tornando assim desnecessária a estrutura condicional switch/case na aplicação cliente. Alcançando dessa forma uma melhor legibilidade do código, pois, cada comando irá instanciar a classe ComandoAdapter, uma maior manutenibilidade e escalabilidade, vez que, sempre que um novo comando for adicionado ao código será através da classe ComandoAdapter.

A Figura 4 ilustra a criação da classe Mensagem que implementa a interface Comando, como pode ser observado na linha 16 e através desse contrato firmado é obrigada a implementar o método executaComando() como é visto na linha 34.


Figura 4 - Classe Mensagem


Fonte: Elaborada pelo autor.


Em uma plataforma Cliente-Servidor a aplicação Cliente pode tanto consumir recursos oferecidos pelo Servidor instanciando o objeto Socket quanto oferecer recursos para que o Servidor os consuma, instanciando o objeto ServerSocket e vice-versa.

O Cliente instancia um objeto SocketServet (servidor) e aguarda conexões na porta 12345, já a aplicação Servidor irá instanciar um objeto Socket (cliente), como é visto na linha 26 da Figura 5 para se conectar a essa porta e enviar o comando para o Cliente executar.


Figura 5 – Instancia do objeto SocketServet


Fonte: Elaborada pelo autor.


Na linha 40 pode-se observar a criação do objeto Mensagem que será passado como parâmetro na linha 42 paro o objeto ComandoAdapter e ao invés de enviar Strings através da conexão via socket envia-se o objeto genérico adapter como é mostrado na linha 44 da figura 5.

Na Figura 6 é demonstrada a estrutura da classe da aplicação Cliente onde tem-se a criação do objeto ComandoAdapter na linha 53 que irá receber o objeto de mesmo tipo vindo da aplicação Servidor. Na linha 55 a execução do método executaComando() pertencente ao objeto Mensagem que foi lido pelo socket na linha 54.


Figura 6 –Estrutura da classe aplicação cliente


Fonte: Elaborada pelo autor.


5. CONCLUSÃO

O presente trabalho apresentou as vantagens da refatoração do código de um sistema legado desenvolvido utilizando a linguagem de programação Java. O principal objetivo foi implantar melhorias a esse sistema legado, aplicando-se técnicas de programação, tais como uso de orientação a objetos de maneira adequada e aplicação de padrões de projeto.

Uma quantidade relevante de código foi removida tanto da codificação da aplicação servidor quanto da cliente tirando assim parte da responsabilidade do cliente em identificar qual classe executaria o comando recebido. O Quadro 2 apresenta um comparativo dos pontos de melhorias no código refatorado.


Quadro 2 – Comparativo entre os sistemas.


LEGADO

REFATORADO

Quantidade de classes

13

16

Quantidade de linhas de código

2009

1798

Quantidade de métodos

93

88

Média de linhas de código por métodos

10,12

7,10

Fonte: Elaborada pelo autor.


A partir destes resultados pode-se observar que houve uma redução significativa do número de linhas e métodos mantendo as características e funcionalidades do sistema legado, demonstrando assim a importância do uso de padrões de projeto no desenvolvimento de software, pois assim é possível desenvolver sistemas mais enxutos e escaláveis, agilizando o processo e facilitando a manutenção do código.

Como proposta para trabalhos futuros fica a possibilidade de utilizar o padrão de projeto Singleton nas instâncias de sockets para garantir que somente um objeto seja instanciado por vez, entre outros padrões, visando demonstrar suas características e vantagens, demonstrando quando devem ser utilizados e como realizar a aplicação de seus conceitos.


ABSTRACT

Refactoring provides an improvement to a legacy code, using appropriate techniques, a number of benefits, from ease of reading to increased scalability. The purpose of this work is to apply refactoring to legacy software, developed with the Java language and that has been in use since 2013. To support this process, we applied design patterns, specifically the Adapter Pattern, where some classes gave way to implementation of Interfaces and the use of message exchange using Strings was replaced by sending specific objects through socket connections, which now provides the possibility of project expansion by allowing full reuse of implemented code.


Keywords: Refactoring. Adapter Pattern. Interface. Java.



REFERÊNCIAS


DEVMEDIA. Disponível em: https://www.devmedia.com.br/conheca-os-padroes-de-projeto/957>. Acesso em 04 de dez de 2017.

Eckel B - Thinking in patternswith Java Slideshare. Disponível em: https://www.slideshare.net/raffaelladangelo98/e-book-pdf-thinking-in-patterns-with-java > Acesso em 18 de dez de 2017.

FOWLER M,‎ BECKK, BRANTJ, OPDYKE W,‎ ROBERTS D - Refactoring: Improvingthe Design ofExistingCodeAddison-Wesley Professional 2012.

GAMMA E ,HELM R,JOHNSON R,VLISSIDES,J.ApplyingUmlandPatterns:AnIntroductiontoObject-OrientedAnalysisand Design andtheUnifiedProcessAddison Wesley, 2003.

GAMMA E.Design Patterns – Elements of Reusable Object-Oriented Software. Addison-Wesley, 1994.

GAMMA E. Padrões de Projeto - Soluções reutilizáveis de Software orientados a objetos.BRASIL,2000.

GUERRA, E. Design Patterns com Java – Programação Orientada a objetos guiado por padrões. Casa do Código. Disponível em: https://www.casadocodigo.com.br/products/livro-design-patterns> Acesso em 19 de nov de 2017.

JAQUES, P.Programação Avançada em JAVA - Disponível em http://www.netsoft.inf.br/aulas/4_SIN_Programacao_Cliente_Servidor/Programacao_Avancada_de_Java.pdf> Acesso em 02 de dez de 2017.