Parte I | Parte II | Parte III | Parte IV | Parte V | Parte VI
O que esperamos de um software? Com certeza, valor. Neste artigo vou falar um pouco sobre a importância do projeto de software, de como esta atividade agrega valor, e também sobre alguns critérios que podem ser utilizados para a avaliação do projeto, finalizando com uma visão geral sobre princípios importantes no uso da orientação a objetos, denominados SOLID (os quais pretendo retomar com detalhe nos próximos posts).
O que esperamos de um software? Com certeza, valor. Neste artigo vou falar um pouco sobre a importância do projeto de software, de como esta atividade agrega valor, e também sobre alguns critérios que podem ser utilizados para a avaliação do projeto, finalizando com uma visão geral sobre princípios importantes no uso da orientação a objetos, denominados SOLID (os quais pretendo retomar com detalhe nos próximos posts).
O que esperar do software
Os usuários sempre esperam obter alguma
espécie de valor do software em uso. Esta noção de valor é
determinada pela capacidade do software
em: auxiliar o usuário a fazer algo melhor ou mais rápido ou ambos; o que
significa aumentar a produtividade do usuário e, com isso, aumentar ganhos (de
tempo, de qualidade ou financeiros) e reduzir também retrabalho e desperdícios
(que representa reduzir custos, que também é outra forma de aumentar os
ganhos).
Assim, o valor do software decorre dos ganhos que seu uso pode proporcionar.
Para que o software possa, de fato, possibilitar ganhos, as necessidades do
cliente, vistas em seu contexto, devem ser entendidas com clareza. Mas isto não
basta.
Projeto de software
Dado um problema para o qual se pretende
obter uma solução por meio de um software, é necessário realizar sua análise e,
depois, o projeto da solução desejadas.
A análise
se ocupa do entendimento do (domínio do) problema e pretende determinar o que
deve ser feito para solucioná-lo. Para tanto a etapa de análise constrói um modelo
conceitual da solução determinada.
O propósito do projeto é determinar
como construir uma solução para o modelo definido pela análise, ou seja, seu
objetivo é definir como tal modelo pode ser construído (ou programado, no caso
do desenvolvimento de software).
A principal diferença entre a análise e o projeto é que a primeira
envolve contato e a discussão com o cliente sobre a construção da solução
conceitual. Já o projeto engloba detalhes relativos ao trabalho do programador,
que em geral, não são de interesse do cliente.
Deve ficar claro que precisamos tanto de um
trabalho de análise, como de projeto, bem feitos. É bastante típico
que seja desejado que a análise e o projeto de software sejam realizados de
maneira rápida, produzindo um software que atenda plenamente as necessidades de
seus clientes, além de ser robusto, seguro e interoperável.
Outra maneira de observar a questão é
procurar as características indesejáveis de um projeto de software, ou seja,
aquilo que identifica um projeto ruim. Um projeto ruim é algo que,
inevitavelmente leva ao software rot.
Software ROT
A expressão software rot, algo como "software
podre", é semelhante aos termos code rot, bit rot, software
erosion, software decay. Todas as expressões mencionadas descrevem a
percepção do usuário sobre a deterioração da performance ou da funcionalidade
do software ao longo do tempo, que progressivamente reduz sua utilidade, até
que este se torne obsoleto ou inutilizável. Mas como isso pode ser verdade se
um programa de computador não sofre qualquer tipo de envelhecimento físico? A
questão aqui não é física, mas contextual.
Uma das principais causas do envelhecimento
de um software é a evolução do seu contexto de utilização. Um programa pode ser
bem projetado e implementado, atendendo plenamente as necessidades de seus
usuários no momento em que é introduzido no mercado. A percepção nesta situação
é o programa atende ou excede as expectativas existentes. Mas à medida que em
que é usado, é bastante natural que os usuários percebam novas possibilidades
para sua utilização, nem todas sendo atendidas pelo projeto inicial. Agora a
percepção do usuário é que o software, mesmo que ainda bom e útil, poderia ser
melhor. Esta piora da percepção é um sinal de envelhecimento.
Quanto maior o tempo, maior será a
deterioração percebida em função da evolução das condições de uso do software.
Produtos concorrentes que exibam diferenciais, além de defeitos observados no
produto, acelerarão o processo de percepção de deterioração, quando, de fato, o
software continua exatamente o mesmo.
A manutenção contínua do software, no
sentido de corrigir-se os defeitos percebidos e, principalmente, incorporação
de novas funcionalidades evolutivas, possibilitarão restaurar, no todo ou em
parte, a percepção inicial de qualidade.
Sendo assim, a ausência ou insuficiência de
manutenção causa a degradação do software, não em decorrência de envelhecimento
real, mas sim da alterações nos requisitos de uso deste software.
Outro sentido de software rot, e das expressões semelhantes, se refere a implementação
de aplicações que, por conta de deficiências no projeto, na documentação e na
própria manutenção, se tornam uma massa desorganizada de código improvisado que
os desenvolvedores tem dificuldade crescente em manter.
Projetos de Software::critérios de avaliação
Existem quatro critérios importantes para
avaliar a qualidade de um projeto de software:
- Rigidez;
- Fragilidade;
- Imobilidade; e
- Viscosidade.
Critério da Rigidez
Este
critério representa a imprevisibilidade do impacto relativo a uma mudança. Em um projeto rígido, toda e qualquer alteração causa uma sucessão
de mudanças em módulos dependentes, produzindo um efeito dominó ou cascata,
que representa a propagação indesejada da alteração efetuada. Assim, uma
tarefa, em tese, simples, torna-se um trabalho hercúleo e, com isto os custos
das alterações são imprevisíveis, bem como o tempo necessário para sua
realização.
Critério da Fragilidade
Dizemos
que um software é frágil quando tende a apresentar problemas em muitos pontos
em cada mudança. Ou seja, as alterações efetuadas em um
ponto do software acabam por causar problemas em outros pontos não relacionados
conceitualmente. Assim, em cada reparo o software apresenta novos problemas não
previstos, novamente com implicações negativas no custo e no tempo da
manutenção.
Critério da Imobilidade
Em função
de como um software é projetado, pode se tornar muito difícil, ou quase
impossível, reutilizar partes do software em outros projetos, caracterizando a
imobilidade (as parte de um software não podem ser movidas para outros). Desta
maneira, mesmo os módulos úteis exibem muitas
dependências com outras partes do software, dificultando ou impedindo seu reuso
em outros projetos. Nesta situação, o custo de reescrever (refazer) acaba
sendo menor do que o risco de separação das partes em função da imobilidade
+ rigidez + fragilidade.
Critério da Viscosidade
Também
existem situações onde as deficiências no projeto ou em sua documentação,
acabam estimulando a realização de pequenos consertos improvisados. Tais remendos
(patches) são mais baratos de implementar do que os reparos maiores que
proporcionariam soluções mais efetivas no projeto como um todo. Assim, a preservação consistente do projeto vai se tornando cada
vez mais difícil de idealizar e implementar, tornando-o viscoso.
A razão central de todos esses problemas é
o projeto mal feito, ingênuo, apressado, improvisado ou incompleto.
Bons projetos não são rígidos,
possibilitando alteração que não se propagam no código; não são frágeis,
garantindo que mudanças em um ponto não façam surgir problemas em módulos não
correlatos; nem impõe a imobilidade; pois suas partes podem ser reutilizadas em
outros projetos; muito menos viscosos; favorecendo que a manutenção seja
realizada de maneira adequada. Então, bons projetos requerem conhecimento
técnico, dedicação e, tão importante quanto isso, que práticas ruins sejam
evitadas, enquanto práticas boas sejam adotadas.
Projeto de Software::características desejadas
Existem algumas características de são
desejadas em qualquer projeto de software, independentemente de seu tamanho ou
complexidade. Aqui podemos destacar dois conceitos centrais na construção de
software: coesão e acoplamento. Além destes, também se
deseja a componibilidade, a independência de contexto e a facilidade para teste.
Projeto
de Software::características desejadas::coesão
O termo coesão (cohesion) foi
definido por Tom DeMarco em 1979 e afirma que:
Cada módulo
deve possuir apenas uma responsabilidade.
Isso implica em dividir as diversas
responsabilidades identificadas na análise e no projeto em módulos distintos,
de maneira que cada um possua apenas as características e funcionalidades estritamente
necessárias à sua responsabilidade.
Num projeto orientado a objetos isto nos
faria pensar sobre:
- Quão bem os métodos e atributos de uma classe se articulam para definir seus propósitos?
- Como uma classe se articula com as outras, sem descaracterizar seus próprios objetivos?
Assim, idealmente no projeto OO, cada
classe deve possuir apenas uma responsabilidade, ficando claro seu
próprio papel e propósito.
As implicações da coesão em um projeto são
boas, pois:
- As alterações necessárias se concentram em módulos específicos;
- Torna-se mais fácil reutilizar aquilo que tem funcionalidade claramente delimitada.
Como é provável que a coesão absoluta seja
difícil de obter, deseja-se que seja a maior ou mais alta possível, pois mais
benefícios trará para o projeto durante sua implementação e também durante sua
manutenção.
Projeto
de Software::características desejadas::acoplamento
Esta
outra característica se relaciona às dependências entre os módulos (classes num
projeto OO) de um sistema. Deseja-se que cada módulo possua o menor número
possível de dependências com outros módulos, ou seja, que os módulos sejam o
mais independentes possíveis e, desta maneira, o acoplamento seja pequeno ou
baixo.
As
implicações do baixo acoplamento são:
·
Concentração das alterações em
módulo específicos;
·
Menor a propagação das
alterações efetuadas; e
·
Maior a chance de
reaproveitamento (reuso) dos módulos.
No entanto, deve-se observar que o acoplamento não é um mal em si, pois algum grau de acoplamento é inerente a
criação de um sistema. Se um módulo não depende de nenhum outro, temos
que seu acoplamento é zero. Mas se todos os módulos são assim, não existe um
sistema, mas um amontoado, provavelmente inútil, de classes.
Isto significa que o acoplamento também é a extensão com que duas ou mais partes de um
sistema estão relacionadas para criar mais valor do que partes individuais.
Um grau adequado de acoplamento permite criar um sistema funcional,
compreensível e manutenível.
Projeto::características
desejadas::componibilidade
Deseja-se
que os módulos de um projeto sejam componíveis, ou seja, que possam ser
combinados de maneiras diferentes, produzindo funcionalidades distintas. Esta
característica implica em:
·
Acrescentar novos módulos e,
com isso, novas funcionalidades;
·
Modificar, no sentido de corrigir
ou melhorar, os módulos existentes; e
·
Também facilitar o teste de
cada componente.
O grande valor da componibilidade é o reuso das partes elaboradas para um sistema na
construção de outros sistemas.
Projeto::características
desejadas::contexto
Além do
interesse em criar componentes que possam ser rearranjados e reutilizados,
também se deseja que tal reuso possa ocorrer em contextos diferentes, ou seja,
para auxiliar na solução de problemas existentes em outros domínios.
A independência
de contexto possibilita:
·
Reutilizar os componentes do
projeto para outros propósitos, em domínios diferentes;
·
Reuso ampliado, o que é um
grande benefício.
Projeto
de Software::avaliação das características desejadas
Observando-se em conjunto as
características boas e ruins dos projetos, nota-se que estão correlacionadas.
Muito da rigidez, da fragilidade, da imobilidade e da viscosidade são
decorrentes da multiplicidade de papeis dos módulos existentes (i.e., de sua baixa
coesão) e também da interdependência excessiva entre suas partes (i.e., de seu
alto acoplamento). Tudo decorrência de projetos descuidados nesse sentido.
No projeto orientado a objetos (OO
Design) as classes tem papel fundamental, pois são os elementos
construtivos dos sistemas. Como modificações no escopo de qualquer sistema
são inevitáveis com o passar do tempo, classes bem projetadas permitirão:
- Codificação mais rápida;
- Teste mais abrangente; e
- Manutenção facilitada.
Para projetar boas classes e, com isso,
construir bons sistemas, existem aspectos importantes que podem e devem ser
observados, como indicam os princípios SOLID.
Princípios SOLID
Em 1995 Robert C. Martin (também conhecido
como Uncle Bob) propôs um amplo
conjunto de princípios de projeto e programação orientada a objetos que,
posteriormente, tornaram-se conhecidos como SOLID, um acrônimo criado por Michael
Feathers para designar os primeiros cinco dos princípios propostos.
A intenção destes princípios é orientar o
programador na construção de sistemas mais fáceis de manter e ampliar com o
passar do tempo, pois sem isso os softwares envelhecem e são percebidos como
deteriorados.
Os princípios enunciados por Martin constituem
um guia para refatoração do código, e também se enquadram nas estratégias ágeis
e na abordagem adaptativa de construção de software.
O acrônimo SOLID é formado por:
- Single Responsability Principle (Parte II)
- Open-Closed Principle (Parte III)
- Liskov`s Substitution Principle (Parte IV)
- Interface Segregation Principle (Parte V)
- Dependency Inversion Principle (Parte VI)
Estes cinco princípios podem ser,
resumidamente, entendidos como segue.
O Single
Responsability Principle ou Princípio
da Responsabilidade Única afirma que uma classe deve ter uma, e apenas uma,
razão para mudar. Assim, cada classe deve representar apenas um ator ou
entidade, devendo ser escrita, modificada e mantida para apenas um propósito
específico.
O Open
Closed Principle ou Princípio
Aberto-Fechado indica que os componentes de um software devem ser abertos
para extensão e fechados para modificação. Isto significa que as classes e
interfaces devem ser pensadas para permitir que sejam estendidas (pela
mecanismo da herança), mas não para modificações nelas próprias.
O Liskov’s
Substitution Principle ou Princípio
da Substituição de Liskov determina que quaisquer tipos derivados (subclasses
ou classes derivadas) devam ser completamente substituíveis por seus tipos base,
de modo que tais substituições sejam transparentes e não causem qualquer erro.
O Interface
Segregation Principle ou Princípio
da Segregação de Interfaces requer que os clientes de módulos de software
não devam ser forçados a
implementar métodos desnecessários que não sejam
usados, reduzindo a burocracia .
O Dependency
Inversion Principle ou Princípio da Inversão de Dependência estabelece a
conveniência de um módulo depender de outros módulos mais abstratos, ao invés
de elementos concretos (de substituição mais complexa).
A aplicação destes cinco princípios permite
melhorar, e muito, a qualidade do software construído para qualquer projeto e,
por isso, cada um merece mais atenção. Mas isto fica para os próximos posts!
Para Saber Mais
- LARMAN, Craig. Utilizando UML e padrões: uma introdução à análise e ao projeto orientados à objetos e ao Processo Unificado. Porto Alegre: Bookman, 2007.
- MARTIN, R. C.; et. al. Clean Code: a handbook of agile software craftsmanship. Boston: Pearson Education, 2009.
- MARTIN, R. C. The Clean Coder. Upper Sadle River: Prentice-Hall, 2011.
- MARTIN, R. C. Principles of OOD. Disponível em http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod, recuperado em 17/02/2017.
- MARTIN, R. C. Get a SOLID start. Disponível em http://objectmentor.com, recuperado em 17/02/2017.
- PAGE-JONES, Meilir. Fundamentos do Desenho Orientado a Objetos. São Paulo: Makron Books, 2001.
- SOMMERVILLE, I. Software Engineering. 9th. Ed. Boston: Addison-Wesley, 2011.
Nenhum comentário:
Postar um comentário