1.3 Dificuldades no desenvolvimento de software
Em seu artigo “No Silver Bullet: Essence and Accidents of Software Engineering”, Brooks (1987) separa as dificuldades no desenvolvimento de software em 2 tipos:
- Dificuldades essenciais: são dificuldades inerentes ao software e não podem ser eliminadas, razão pela qual não existe uma solução milagrosa para melhorar drasticamente a produtividade;
- Dificuldades acidentais: associadas a problemas tecnológicos como linguagens ruins, ferramentas fracas, falta de métodos, etc que podem ser resolvidos pelos engenheiros de software com tecnologia e recursos;
Segundo Brooks, entre as dificuldades essenciais temos:
- Complexidade: softwares são extremamente complexos, com muitas partes independentes, comportamento difícil de prever, crescimento exponencial, etc e não há como simplificar totalmente um sistema complexo;
- Conformidade: softwares precisam se adaptar ao mundo real, exemplo: regras de negócio que podem mudar constantemente como leis, sistemas externos, etc;
- Mutabilidade: consiste na necessidade de evoluir sempre, incorporando novas funcionalidades, correções, adaptações, etc. Na verdade, quanto mais bem sucedido for um sistema de software, mais demanda por mudanças ele recebe;
- Invisibilidade: devido a sua natureza abstrata do software, é difícil visualizar o tamanho e consequentemente estimar o esforço da sua construção, exemplos: uma IDE que possui muitos bugs e travamentos, uma aplicação web pouco intuitiva, um framework que não oferece documentação, etc.
A complexidade é a dificuldade mais crítica atualmente, porque os sistemas modernos são distribuídos, interconectados e estão em constante evolução. Isso aumenta o número de dependências e interações, tornando o sistema mais difícil de entender, testar e manter. Como consequência, pequenas mudanças podem gerar efeitos imprevisíveis, aumentando bugs, custos e reduzindo a confiabilidade.
Um exemplo real para ilustrar a complexidade na construção de softwares reais, temos o caso do Google. Em 2015 a empresa somava 2 bilhões de linhas de código, distribuídas em 9 milhões de arquivos. Nessa época, 40 mil solicitações de mudanças de código por dia eram realizadas, por cerca de 25 mil engenheiros de software.
Um outro exemplo prático da complexidade no desenvolvimento de softwares é o sistema de entregas tipo Uber ou iFood. Ele envolve muitas camadas: app do cliente, app do entregador, backend, sistema de pagamento, geolocalização, notificações, etc. Com isso, o sistema é composto por várias dependências: vários clientes pedindo e vários entregadores aceitando. Além disso, o backend envolve vários sistemas distribuídos: pedidos, pagamento, entrega, etc. Podem haver também mudanças constantes como: taxas dinâmicas, promoções, fretes por região, etc. Casos extremos podem ocorrer, como: entregador cancela no meio, cliente muda o endereço, app fica offline, etc. Com isso, muitos problemas podem ocorrer e, se uma parte falha, todo o sistema quebra. Imagina se dois entregadores aceitam o mesmo pedido, se a comunicação entre os serviços falhar, se o cliente pagar e não receber… isso pode gerar bugs difíceis de reproduzir, erros intermitentes, comportamento imprevisível, sistemas difíceis de testar e muitos outros problemas que podem comprometer o funcionamento correto do sistema. A complexidade surge não dos componentes individuais, mas das interações entre eles.
Bibliografia:
Marco Tulio Valente. Engenharia de Software Moderna: Princípios e Práticas para Desenvolvimento de Software com Produtividade, Editora: Independente, 2020.
SOMMERVILLE, Ian. Engenharia de software. 9. ed. São Paulo: Pearson Prentice Hall, 2011.