Evolução de Software e a Importância da Refatoração
Tags: programming, cleancode, softwareevolution, refactoring
Published: 2022-12-26 19:33:53

# Evolução de Software

## O que é Evolução de Software?

Evolução de Software é o processo de desenvolvimento, modificações  e atualizações que o software sofre ao longo do tempo.

## A importância da Evolução de Software

Com o passar do tempo, a complexidade de um software aumenta e junto com ela, o seu tamanho também. Ou seja, mais código para realizar manutenção e maior dificuldade de encontrar e solucionar bugs.

O envelhecimento de um software é inevitável, portanto é preciso que os conceitos da evolução de software estejam presentes em seu processo de desenvolvimento.

## Como prevenir futuros problemas?

Algumas maneiras de prevenir os problemas que o tempo de vida de um software pode trazer são:

- **Transparência**:
    
    Manter todas as partes envolvidas no software cientes do escopo, propósito e regras de negócio do sistema em desenvolvimento. Inclusive de possíveis modificações ao passar do tempo.
    
- **Realizar abstrações**:
    
    Sempre que possível, realizar abstrações para agilizar o desenvolvimento e diminuir repetição de código
    
- **Modularização**:
    
    Dividir o sistema em módulos para facilitar a manutenção ao longo do tempo. Além de facilitar detecção de erros, realização de testes e permitir o desenvolvimento independente dos módulos
    
- **Amputação**:
    
    Em casos extremos, quando algo está apresentando muitos problemas e não é possível resolver, talvez seja melhor analisar a possibilidade de remover a feature por completo
    

## Manutenção x Desenvolvimento

A partir disso, é importante abrir espaço entre, ou durante, as etapas de desenvolvimento para realizar manutenção do software para que, no futuro, não ocorram problemas decorrentes disso.

Para realizar as devidas manutenções, é preciso passar por algumas etapas para entender o propósito das mesmas.

É preciso, primeiramente, de um conhecimento profundo da estrutura do sistema, ou da funcionalidade em questão, isso podemos adquirir a partir de documentações muito bem escritas ou designando esta tarefa para a pessoa que mais teve contato com a funcionalidade.

Também é bastante importante entender e levantar o impacto que mexer nessa funcionalidade pode causar. Por isso reforço a importância da documentação, que é possível evitar novos erros a partir do histórico de problemas antigos.

Em sequência, é necessário realizar as estimativas de custo ou de tempo que essa manutenção pode causar para que ela seja devidamente incluída dentro da sprint e, por fim, documentar todas as mudanças realizadas.

### Problemas que a falta de manutenção pode causar:

É importante destacarmos que a manutenção é extremamente importante para garantir a Manutenibilidade do software, que é a facilidade com que é possivel modificar o sistema.

Quando não há manutenção, ou há manutenção ruim, pode coasionar em perda de tempo para desenvolver novas funcionalidades, um cliente insatisfeito, redução na qualidade do produto e até mesmo insatisfação do próprio time de desenvolvimento pois irá gerar dificuldade para corrigir o problema futuramente e novamente.

### Coisas que podem afetar a manutenibilidade do sistema:

Por si só a evolução do software é dificil de se manter por muitos anos e isso deve ser levado em consideração. São muitos processos, classes, linhas de código e a complexidade aumenta com o passar do tempo. Isso impacta diretamente na manutenilibidade. Por isso é fundamental estabelecer padrões referentes a linguagem de programação, realizar testes e versionar o código.

Assim como, é dificil documentar todas as alterações e processos de forma que todos os desenvolvedores estejam 100% cientes de tudo. 

E por fim, a visão que algumas pessoas tem de que manutenção é sinônimo de um trabalho ruim. O que não é verdade! Código cresce com o passar do tempo, a complexidade aumenta e a manutenção é fundamental para que o software continue vivo e funcionando da maneira esperada. É preciso haver, ou criar, espaço para aprimorar a manutenibilidade.

# Refatoração

Dentro da engenharia de software, temos muitas formas de realizar a manutenção do código. Diversos conceitos, ferramentas e metodologias, contudo, hoje vamos focar na Refatoração.

## O que é refatoração?

Refatoração é o processo de alterar um sistema afim que seu comportamento não seja modificado, mas sua estrutura interna seja melhorada. O objetivo por trás disso é reduzir a complexidade e tornar o software mais compreensível, basicamente é melhorar a qualidade do software.

## Quando podemos refatorar?

Alguns momentos ideiais para realizar a refatoração de um código, são quando:

- Houver tempo entre as etapas de desenvolvimento
- Durante a etapa de Code Review (seja ao enviar o MR ou na revisão que fazemos enquanto desenvolvemos)

## Quando não refatorar?

- Quando está muito perto do prazo final de entrega
- Quando o código tá muito confuso (neste caso é recomendado a reescrita total)
- Quando o código apresenta muitos bugs
- Depois

### O “Consertar Depois”

Sempre que possível, refatore e aprimore o código no momento que você identificar algum indicativo que é preciso. Pois, muito provavelmente, se você deixar para depois, as chances de retomar para refatorar são menores.

**Poque não deixar para “depois”?**

- **Perda de contexto e confiaça**
    
    Quanto mais você estiver removido do ponto em que o código foi escrito, menos você o entende. E se você não consegue lembrar todos os casos de uso, não tem mais a mesma confiança em alterar por medo de quebrar a funcionalidade. Portanto o risco de quebrar não  "vale” o benefício da melhoria.
    
- **Normalização**
    
    Quanto mais você convive com algo, mais acostumado você está com isso e cada vez menos é uma prioridade.
    
- **Maior Prioridade**
    
    Sempre há uma coisa nova que queremos construir ou melhorar. Eventualmente, o que antes era um problema, acaba virando o normal e outra coisa ganha prioridade.
    
- **Agora você está confiando naquele código**
    
    Mesmo sabendo que o código é ruim, ainda sim é preciso implementar coisas novas. Isso acaba criando um ciclo onde tudo que vem de novo, acaba ficando dependente daquele código ruim e acaba ficando mais dificil de realizar manutenção.
    

## Como identificar se o código precisa de refatoração?

Uma forma de identificar se um código precisa de refatoração a partir da presença de “Bad Smells”.

### O que é Bad Smell?

Bad Smell é basicamente algumas más práticas de desenvolvimento que podem ser aprimorados com refatoração.

### Classe Deus

A classe Deus é uma classe que realiza muitas coisas dentro do sistema. Ela pode ter muitos atributos, muitas funções e muitas responsabilidades.

**Como resolver?**

- Dividir em classes menores
- Criar subclasses que se relacionem melhor com a classe principal
- Verificar se os atributos e métodos são todos necesários

### Método Deus

São métodos extensos que centralizam toda funcionalidade de uma classe. Altamente dificeis de manter e de entender.

**Como resolver?**

- Dividir o método em outros menores
- Verificar a possibilidade de transformá-lo em uma classe

### Funcionalidade Invejosa

Parte de uma classe que só utiliza atributos e métodos de outra classe específica.

**Como resolver?**

- Verificar a possibilidade de mover os atributos e métodos em questão entre as classes
- Verificar se vale a pena juntar as classes em uma, ou utilizar conceitos de sub-classes para dividir melhor as responsabilidades

### Comentários

Comentários não é necessariamente algo ruim. Eles podem ser utilizados para auxiliar na compreensão do código, contudo, se for em excesso pode atrapalhar a legibilidade do mesmo.

**Como resolver?**

- Remover comentários desnecessários
- Simplifique o código (Se algo está muito complexo à nível de necessitar de um texto para compreender, a melhor abordagem é simplificar o código ao invés de escrever um texto explicando o mesmo)

### Mudanças Divergentes

Quando uma classe muda frequentemente de forma com razões distintas.

Por exemplo: Uma classe que originalmente estava responsável por controlar a página de login, foi alterada e agora o novo escopo dela é controlar a página de cadastro, e foi alterada novamente e agora ela é responsável por controlar o fluxo de onBoarding.

**Como resolver?**

- Dividir a classe: Cada mudança de escopo deve ficar em uma classe separada

### Shotgun Surgery

Quando ao alterar uma classe, é necessário alterar várias outras.

**Como resolver?**

- Reorganizar as responsabilidades e divisões das classes afetadas e verificar a possibilidade de junção de classes ou mover os métodos e atributos para se enquadrar melhor ao escopo

### Classe Reclusa

Uma classe que herda atributos e métodos de outra classe, mas não utiliza para nada.

**Como resolver?**

- Reformular a hierarquia das classes em questão

### Lista de Parâmetro muito Grande

Uma classe com parâmetros em abundância.

**Como resolver?**

- Verificar a possibilidade de remodelar o algoritmo a fim de que não seja preciso parametros em excesso para que a feature funcione de maneira apropriada

### Anti-Patterns

Algumas más práticas que vão de encontro à boas práticas de desenvolvimento.

- **Blind Faith**: Não checar a correção de um bug
- **Boat Anchor**: Parte do sistema sem uso
- **Lava Flow**: Código ruim colocado em constante mudança sem ser refatorado
- **Gold Hammer**: Tecnologia familiar aplicada em todos os problemas
- **Cult Programming**: Utilizar padrões sem saber o motivo
- **Lasagna Code**: Código com muitas camadas desnecessárias
- **Spaghetti Code**: Estruturas de código pouco compreensíveis

## Como planejar a manutenção?

Uma sugestão para melhor planejar a manutenção do software é, além de aplicar os conceitos mencionados atenriormente quando necessário, também alinhar um período de manutenção dentro da sprint.

Uma sugestão seria a equipe não passar imediatamente para a próxima feature, mas sim ter um tempo de melhoria para que o que for entregue, tenha menos chances de apresentar problemas e aumente a manutenibilidade do software.

É claro, que não é preciso alocar esse tempo entre cada sprint. Mas é importante ter essa possibilidade analisada e manter uma certa periodicidade para as necessidades referentes à manutenção do sistema.

## Como aumentar a periodicidade da necessidade de manutenção?

Algumas formas de aumentar a periodicidade é basicamente tentar se manter fiel aos conceitos de código limpo, planejar bem, entender o problema que você quer resolver e testar bem a solução implementada.

### Definir Metas Claras

Tenha em mente, de forma clara e visível, as metas que o código quer resolver. Isso é fundamental em situações onde é preciso decidir como adicionar uma feature nova ou se deve ser aceita uma mudança de escopo.

### Defina as Restrições

Também tenha em mente quais problemas seu código não resolve. Restringir o escopo é importante e é uma forma de te forçar a focar exclusivamente no problema.

### Dizer Não

Sempre vai ter algo novo e importante para ser implementado. A importância de dizer não, quando couber, garante que o software não cresça de forma descontrolada. 

### Elimine Resíduos

Sempre que possível, remova quaisquer recursos não utilizados e código morto.

### Minimize Dependências

Ser exigente ao adicionar dependências, considerar prós e contras. Pois dependências podem quebrar, desaparecer, se tornar um risco de segurança. Se a funcionalidade for crucial para o produto, vale a pena avaliar se não é melhor implementar você mesmo.

# Conclusão

Para resumir, evolução de software é algo que tem que ser olhado com atenção para que o sistema tenha possibilidade de crescer junto com o tempo. Para isso, é importante garantir a manutenibilidade do sistema com manutenção periódica, que deve ser planejada e não ser feita somente quando a situação ta critica.

Uma forma de fazer a manutenção é através da refatoração, que melhora o código internamente, sem afetar a funcionalidade para o usuário final. Para identificar se há necessidade de refatoração, é importante se atentar à presença de “Bad Smells”.

E para aumentar o período em que uma manutenção deve ser feita, é preciso se manter fiel aos conceitos de código limpo, planejar bem, entender o problema que você quer resolver e testar bem a solução implementada.

# Referências

[Stop lying to yourself – you will never “fix it later”](https://uselessdevblog.wordpress.com/2022/11/10/stop-lying-to-yourself-you-will-never-fix-it-later/)
[Best practices for building scalable Flutter applications](https://verygood.ventures/blog/scalable-best-practices)
[Your Code Doesn't Have to Be a Mess](https://www.danielsieger.com/blog/2022/07/25/your-code-doesnt-have-to-be-a-mess.html)
[Lean software development](https://en.wikipedia.org/wiki/Lean_software_development)
[Keep it Simple, Over Time](https://www.danielsieger.com/blog/2022/03/30/kiss-over-time.html)