Resumo. A engenharia de software abrange toda uma organização para o desenvolvimento de uma solução para um negócio crítico. Neste artigo abordaremos a respeito da engenharia, arquitetura e evolução de software a partir dos conceitos iniciais acerca do assunto, etapas da engenharia, processos, gestão de equipes para o alcance da qualidade de software, assim como metodologias ágeis de desenvolvimento que estão integralmente aliadas à engenharia de software.
A Engenharia de Software trabalha com os aspectos de desenvolvimento de um sistema. Para isso, conceitos da engenharia são incorporados na área de TI, como conceitos de gerenciamento, metodologias, práticas e ferramentas as quais possam contribuir e facilitar para um melhor desenvolvimento de um sistema.
Quando se fala de arquitetura de software, é bastante intuitivo trazer o papel de um arquiteto convencional para a área de TI. Este tipo de pensamento não é errado, visto que a arquitetura de software é de grande importância, passando desde a concepção de um sistema até a sua estruturação, sendo essa última dependente da característica crítica do sistema. Sua estrutura pode se alterar bastante, a depender da demanda, objetivo final e escala do sistema.
Por último, temos a evolução de software, que se trata de etapas que um sistema atravessa até ser entregue ou liberado. Estas etapas podem ser bastante diversificadas, a depender do tipo de sistema e do tipo de solicitação de mudança. A solicitação pode ser de adequação a alguma plataforma, reparo de defeitos, entre outros objetivos. Neste artigo, discutiremos os principais aspectos da engenharia, arquitetura e evolução de software, ilustrando o que significa cada passo, a fim de que o leitor possa, ao término da leitura, diferenciar cada um destes pontos.
A engenharia de software nada mais é do que uma área onde envolvem-se todos os aspectos do desenvolvimento de um software. É a aplicação dos conceitos de engenharia ao desenvolvimento de software. Obviamente, respeitando as diretrizes e etapas para a produção de determinada ferramenta (o software).
Pressman define a engenharia de software como “[…] um processo, um conjunto de métodos (práticas) e um leque de ferramentas que possibilitam aos profissionais desenvolverem software de altíssima qualidade”. (Pressman, 2016, p. 14). Assim como o IEEE, que conceitua a engenharia de software como “uma aplicação sistemática, disciplinada e quantificável no desenvolvimento, na operação e na manutenção do software […]”.
A engenharia de software possui algumas camadas e está inteiramente associada à qualidade, ao aperfeiçoamento dos processos, assim como a melhorias da disciplina. A figura que segue demonstra tais camadas.
Figura 1. Camadas da Engenharia de Software
Sommerville destaca que o processo de software é “um conjunto de atividades relacionadas que levam à produção de um produto de software”.
O processo de software é utilizado tanto no desenvolvimento quanto na evolução do software. Nessa camada da engenharia de software é onde estão as quatro atividades fundamentais para a engenharia de software.
1. Especificação de software: a funcionalidade do software e as restrições a seu funcionamento devem ser definidas.
2. Projeto e implementação de software: o software deve ser produzido para atender às especificações.
3. Validação de software: o software deve ser avaliado para garantir que atenda às demandas do cliente.
4. Evolução de software: o software deve evoluir para atender às necessidades de mudança dos clientes. (SOMMERVILLE, 2011, p. 18).
Há ainda os modelos de software a serem seguidos, que estabelecem meios de organização do desenvolvimento do artefato a ser entregue. Sommerville apresenta três modelos principais de processo de software a serem seguidos: o modelo em cascata, o desenvolvimento incremental e o modelo de processo de engenharia de software orientada a reúso.
O Modelo de Processo em Cascata foi um dos primeiros modelos de processo a ser desenvolvido. Ele é baseado em processos gerais da engenharia de software. Suas fases são encadeadas, uma depende da conclusão da anterior para ser iniciada, por isso muitos autores, como Mary Hanna, questionam a eficácia desse processo de software. Segue o esquema do processo em cascata:
Figura 2. Camadas da Engenharia de Software [Sommerville, 2011]
No Modelo de Processo Incremental existe a descrição inicial do software, logo são desenvolvidas atividades concorrentes para a entrega (especificação, desenvolvimento e validação) para ser disponibilizada uma versão inicial. A partir dessa versão inicial serão executadas versões intermediárias com incrementos de novas funcionalidades e disponibilizadas para uso.
Figura 3. Organograma do Processo Incremental.
O processo de engenharia de software Orientado a Reúso, segundo Sommerville, é baseado “na existência de um número significativo de componentes reusáveis. O processo de desenvolvimento do sistema concentra-se na integração desses componentes em um sistema já existente em vez de desenvolver […] a partir do zero”. Assim, é reduzida a quantidade de código a ser desenvolvido, o que diminui os custos e riscos de produção por ser mais rápido de ser entregue uma solução. Segue um organograma do processo:
Figura 4. Organograma do Processo Orientado a Reúso.
Em 1996, David Hooker enunciou sete princípios da engenharia de software utilizados para ajudar a estabelecer, como diz Pressman: “um modo de pensar para a prática da engenharia de software”. Tais princípios são de grande valia para os desenvolvedores.
Primeiro princípio — a razão de existir: nesse princípio, Hooker destaca que um software existe para agregar valor para seus usuários. Então, as equipes devem ter isso em mente para que antes de especificar qualquer requisito no sistema, procure avaliar se de fato aquilo agregar algum valor ao artefato. Caso não some nenhum é preferível que seja descartado. De acordo com Hooker apud Pressman (2016): “Todos os outros princípios se apoiam neste primeiro”.
Segundo princípio — KISS (Keep It Simple, Stupid!): o projeto deve ser o mais simples possível, atender às demandas de forma simplificada; porém não simplista e, o mais fácil possível de entender e de prestar manutenção. Assim, será alcançado um software menos predisposto a erros.
Terceiro princípio — mantenha a visão: esse é um princípio inteiramente ligado à arquitetura de software. Ele é responsável por manter a integridade do projeto para que todos tenham uma mesma visão sobre o mesmo e trabalhem em prol do mesmo objetivo para evitar que o produto torne-se uma “colcha de retalhos”.
Quarto princípio — o que um produz outros consomem: em um sistema de larga escala ou em um grande projeto é normal que outros profissionais tenham que prestar manutenção e entender o software. Por isso, é necessário que seja desenvolvido pensando que outros terão que entender o que foi feito, assim como é preciso que os usuários entendam como ele funciona de forma clara.
Quinto princípio — esteja aberto para o futuro: Um sistema de grande porte tem um valor mais elevado se possui uma vida prolongada. É preciso desenvolver de forma que o sistema resolva os problemas mais específicos, mas que também atenda à uma demanda geral para que seja reutilizado posteriormente.
Sexto princípio — planeje com antecedência, visando a reutilização: esse princípio diz que a reutilização dos componentes desenvolvidos aumenta o valor dos sistemas e reduz o custo de produção; mas, Pressman informa que o desenvolvimento visando a reutilização pode resultar numa conta cara de produção. É necessário observar se existe a real vantagem no desenvolvimento reutilizável.
Sétimo princípio — pense!: Quando algo é analisado antes de ser executado a possibilidade de dar errado é remota. Assim como pode-se tratar o erro como uma experiência para futuras produções.
“A arquitetura de software lida com com abstração, com decomposição e composição, com estilo e estética” (Kruchten, 1995).
Como podemos ver, com a citação de Kruchten, a arquitetura de software envolve não apenas a parte de lógica, programação e aplicação, mas com o produto como um todo. Itens como estética, tipo de usuário, forma de aplicação, tudo é levado em conta quando falamos de arquitetura de software. Além disso, a arquitetura é o elo que une o projeto e a engenharia de requisitos, identificando os principais componentes do sistema e o relacionamento entre eles. Como resultado do projeto de arquitetura, nós temos um modelo de como o conjunto de componentes se comunica entre si.
De maneira geral, podemos separar a arquitetura em dois níveis de abstração: pequena escala; e grande escala (Sommerville, 2011).
Deve-se manter em mente também que características como desempenho, robustez, manutenibilidade e também sua capacidade de distribuição são medidos e desenvolvidos pela arquitetura de software (Bosch, 2000).
Como sabemos, a produção de sistemas é feita por equipes envolvendo diversas pessoas diferentes, cada uma lidando, às vezes, com um componente diferente. Devido a este fato, é necessário falar sobre a documentação durante todo o processo de produção. Segundo Bass et al. (2003), existem três grandes vantagens de se projetar e documentar, explicitamente, uma arquitetura:
Quando se trata da produção de um sistema, é necessário saber qual será a característica crítica deste sistema, e para isso, existem diversas visões sobre a arquitetura de software (Sommerville, 2011). Para isso, Kruchten (1995) apresentou um modelo de visão “4+1” de arquitetura, sugerindo haver quatro visões fundamentais de arquitetura. São essas: lógica; de processos; de desenvolvimento; física.
A visão lógica, que mostra as abstrações fundamentais do sistema como objetos ou classes de objetos. Nessa visão, deveria ser possível relacionar os requisitos de sistema com as entidades.
A visão de processo, que mostra como, no tempo de execução, o sistema é composto de processos interativos. Essa visão é útil para fazer julgamentos sobre as características não funcionais do sistema, como desempenho e disponibilidade.
A visão de desenvolvimento, que mostra como o software é decomposto para o desenvolvimento, ou seja, apresenta a distribuição do software em componentes que são implementados por um único desenvolvedor ou por uma equipe de desenvolvimento. Essa visão é útil para gerentes de software e programadores.
Uma visão física, que mostra o hardware do sistema e como os componentes de software são distribuídos entre os processadores. Essa visão é útil para os engenheiros de sistemas que estão planejando uma implantação do sistema.
Neste tópico, vamos ver alguns dos padrões mais usados na arquitetura de software. Veremos que cada um destes padrões possuem estruturas que são mais favoráveis para um certo tipo de aplicação (Sommerville, 2011).
Este tipo de arquitetura é estruturado, como seu nome diz, em camadas hierarquizadas. Cada camada irá fornecer informações para as camadas mais acima. Isto quer dizer que as camadas mais baixas na estrutura são as camadas mais fundamentais, que possuem os serviços a serem utilizados em todo o sistema. Por possuir este tipo de estrutura, ela é usada para construir recursos sobre sistemas já existentes, não sendo necessário fazer tantas mudanças estruturais no sistema. Esta forma de estruturar a arquitetura também é bastante útil para a separação de tarefas.
A vantagem de se utilizar esta estrutura é que ao se manter a interface do sistema, é possível fazer a substituição de camadas inteiras. Porém, como desvantagem vemos que é difícil a separação das camadas de maneira prática. Além disso, a questão de desempenho pode ser um problema quando uma camada mais acima necessita trocar dados com camadas mais abaixo. Na Figura 5 temos dois exemplos de estruturas em camadas. Enquanto que o primeiro exemplo é mais generalista, o segundo tem como exemplo uma biblioteca onde possuímos diversos bancos de dados e camadas responsáveis por diferentes acessos.
Figura 5. Exemplo de arquiteturas em camadas [Sommerville, 2011].
Para este tipo de arquitetura, temos um sistema o qual vários componentes se relacionam a partir de um repositório central, o qual gerencia um banco de dados. Este tipo de estrutura é bastante utilizado em sistemas que utilizam um grande volume de dados e que ainda necessitam de compartilhar estes dados entre diversos componentes. Esta estruturação também é utilizada em sistemas dirigidos, os quais a inclusão ou a modificação de um dado dentro do repositório dispara um comando para um diferente componente.
Como vantagem na arquitetura de repositórios, temos o fato de os componentes poderem ser independentes. Isso significa que, por haver um repositório central, é possível desativar componentes para manutenção, atualização, etc, sem comprometer o sistema por inteiro. Além disso, temos a possibilidade de uma administração mais consistente do banco de dados. Porém, a desvantagem neste tipo de estrutura é que qualquer tipo de defeito no repositório pode comprometer o sistema por completo. Além disso, a distribuição do repositório pode ser bastante complicada. Existem questões também como redundância e backup de dados, que pode ser um pouco complexa.
Para esta estrutura nós temos como exemplo a Figura 6, mostrando um repositor de projetos e diversos componentes fazendo seus trabalhos de forma independente e autônoma, sem influenciar a atividade de outro componente.
Figura 6. Exemplo de uma arquitetura de repositores [Sommerville, 2011]
Neste tipo de arquitetura temos uma estrutura mais direta, a estrutura de Cliente-Servidor. Isto significa que o cliente acessa diretamente um determinado servidor para um determinado tipo de serviço. Para que funcione desta forma, cada servidor é responsável por um serviço no sistema. Outra funcionalidade deste tipo de estrutura é a possibilidade de se replicar servidores, para o caso de uma maior demanda de serviço.
Como vantagens temos os servidores poderem ser distribuídos em uma rede. Além disso, temos que uma funcionalidade geral pode estar disponível para todos os clientes, porém não precisa ser implementada por todos os serviços. Como desvantagem, temos que o desempenho pode ser de certa forma imprevisível, visto que o mesmo depende do estado da rede. Outra desvantagem é, caso os servidores sejam administrados por diferentes organizações, o gerenciamento dos servidores pode se tornar bastante complexo.
Como exemplo nós temos a Figura 7 mostrando uma diversos clientes se comunicando através de uma rede com diversos servidores, onde cada solicitação de serviço irá direcionar o cliente a um diferente servidor.
Figura 7. Exemplo de uma arquitetura de servidor-cliente mostrando clientes e servidores se comunicando através da internet [Sommerville, 2011].
Nesta estrutura, cada componente performa um tipo de processamento, chamado de filtro, realizando um tipo de seleção ou alteração no dado. Desta forma, os dados fluem como em um duto e sofrem processos de diversos filtros até chegar como resultado para o usuário.
Como vantagem temos que este tipo de estrutura facilita muito a prática do reúso, além de permitir a possibilidade de implementação de forma sequencial ou concorrente. Como desvantagem, temos que toda a transferência de dados deve ser feita em um formato comum. Na Figura 8 temos um exemplo de um processamento de faturas mostrando diversos componentes realizando um tipo de filtro no dado de entrada.
Figura 8. Exemplo de uma arquitetura de duto e filtro [Sommerville, 2011].
A evolução dos processos de software depende, normalmente, de uma interação entre os usuários e os desenvolvedores.
Em todas as organizações, as propostas de mudança no sistema são os acionadores para a evolução. As propostas de mudança podem vir de requisitos já existentes que não tenham sido implementados no release do sistema, solicitações de novos requisitos, relatórios de bugs do sistema […] e novas ideias para melhoria do software vindas da equipe de desenvolvimento. (SOMMERVILLE, 2011).
Então, os processos de evolução de software são os responsáveis pela implementação de novas funcionalidades ou correção de desenvolvimento para que o sistema sofra uma melhoria como um todo. Sendo que o processo de evolução pode ser representado pelos mesmos organogramas de sua produção, com a ressalva da parte de Planejamento, onde será especificado se é uma correção de bug, adaptação de plataforma ou aperfeiçoamento do sistema.
As metodologias de evolução contemplam as Leis de Lehman, que servem para segmentar o processo de evolução por qual todo software pode vir a passar, manutenção evolutiva, refatoração e reengenharia de software.
As Leis de Lehman são: 1. Mudança contínua, 2. Aumento da complexidade, 3. Evolução de programa de grande porte, 4. Estabilidade organizacional, 5. Conservação da familiaridade, 6. Crescimento contínuo, 7. Declínio de qualidade, sistema de feedback. A primeira diz que todo sistema passará por um processo de manutenção. A segunda diz que tal manutenção fará com que a estrutura do programa se modifique, então é necessário investir em manutenção preventiva. A terceira diz que sistemas grandes têm uma dinâmica própria e isso diz como o processo de manutenção será executado e quantas dessas irão acontecer, já que cada vez que o software é mudado acontece o que é conceituado na segunda lei. A quarta lei diz que a mudança é constante em cada release já que a evolução de grandes projetos já estão trabalhando níveis saturados de entregas, então não adianta a mudança de equipe ou adequação de grandes equipes para projetos de grande porte, já que esse será dominado pelos overheads da equipe. A quinta sugere que a medida que há aumentos de mudanças, existe também a inserção de novos defeitos. A sexta lei diz que as funcionalidades e incrementos devem aumentar para manter a satisfação dos usuários. A sétima que é inevitável o decréscimo da qualidade de um sistema, a menos que ele seja modificado para refletir as mudanças do ambiente operacional ao qual pertence. E a oitava pede a constante observação dos feedbacks para que sempre exista uma melhoria significativa do produto.
A manutenção de software, manutenção preventiva, reengenharia de software ocorre após a liberação do sistema. Normalmente são executadas para efetuar correções de defeitos, adaptação ambiental — onde o sistema sofre uma adaptação para se adequar ao novo ambiente onde está inserido, e a manutenção para adição de funcionalidades.
A refatoração é efetuada para agregar a um sistema de menor qualidade mais qualidade tanto de codificação quanto de processos. O sistema fica com uma compreensão mais simples e mais suscetível à manutenções bem sucedidas.
Na área da Tecnologia da Informação (TI), a Engenharia de Software vem para facilitar todos os processos que antes estiveram sendo executados sem uma certa organização e não segmentados através de diretrizes de construção de software.
Várias outras áreas derivadas da Engenharia de Software surgiram, prosperaram e modificam-se com o passar dos anos para atender à constante evolução da necessidade dos mercados e adequação aos novos paradigmas e atualizações de ambiente.
As metodologias adotadas para a rápida solução de software e de processos de Engenharia de Software também são casos de evoluções na forma de conduzir o desenvolvimento de sistemas. Tais metodologias, como é o caso das metodologias ágeis são aplicadas não somente na produção e codificação de software, mas cresceram dentro do setor de TI e são adaptadas a vários outros setores do mercado.
Então, os conceitos de Engenharia de Software foram estabelecidos justamente para que os desenvolvedores consigam entregar exatamente o que o requerente necessita, dentro do prazo estabelecido e com foco extremo na qualidade do produto final. Por isso, se faz de grande importância o estudo profundo da Engenharia de Software pelos profissionais do setor de TI.