Diretriz: Reutilização de Software
Esta diretriz descreve como reutilizar software e elementos de design.
Relacionamentos
Descrição Principal

A maximização da reutilização tem sempre sido uma importante meta de desenvolvimento de software. É melhor reutilizar o design e o código existentes do que despender recursos na criação, teste, e primeira liberação de algo novo com o risco dos problemas ocultos que todos os novos softwares têm. As linguagens, especialmente as orientadas a objetos, foram desenvolvidas para tornar a reutilização mais fácil. Mas somente a linguagem não é suficiente para fornecer uma reutilização de custo eficaz. A maior parte do software reutilizável vem de arquitetos e desenvolvedores qualificados que são capazes de identificar e alavancar oportunidades de reutilização.

Existem três perspectivas a serem consideradas quando da reutilização de software: código (implementação), design e framework ou arquitetura. Os arquitetos devem buscar a reutilização de significantes frameworks de aplicação, tais como camadas que pode ser aplicadas a muitos tipos diferentes de aplicações. Os desenvolvedores devem buscar os designs e padrões que possam ser reutilizados para produzir o comportamento desejado ou estruturas robustas. Eles devem também procurar uma forma de reduzir a quantidade de código a ser escrito pela alavancagem de código e componentes estáveis que tenham sido usados com sucesso em ambientes de produção.

Identificando Oportunidades de Reutilização

A melhor forma de permitir que uma equipe encontre oportunidades de reutilização é exercer excelentes práticas de design e programação. É difícil encontrar código e design que possam ser reutilizados quando se trata de classes grandes, classes que não possuem um foco bem definido ou classes com relacionamentos que são difíceis de compreender. As classes devem ser pequenas, de fácil compreensão e altamente coesas para facilitar a identificação de oportunidades de reutilização. Qualquer funcionalidade que possa ser razoavelmente separada em outra classe, deve ser. Outra forma de dizer isto é que qualquer conceito que possa ser aplicado a mais de um tipo de classe deve ter a sua própria classe.

Por exemplo, se alguns cálculos são adicionados a uma classe existente, pode fazer sentido a re-fatoração desses cálculos em uma nova classe auxiliar. Esses cálculos podem então ser reutilizados em qualquer outra classe, sem o ônus do conhecimento da funcionalidade da classe original.

A forma mais simples, porem menos eficiente para identificar oportunidades de reutilização é "cheirar" código semelhante. Um desenvolvedor deve recordar de algo que fez semelhante ao que está projetando ou implementado agora. Uma vez que a implementação anterior tenha sido descoberta ou recordada ela poderá ser reutilizada. Os desenvolvedores sempre encontrarão oportunidades de reutilização desta forma. Mas a sua natureza não estruturada não maximizará as áreas potenciais de reutilização.

A colaboração é uma boa técnica para identificar oportunidades de reutilização. Ela fornece uma estrutura onde a identificação da reutilização - ao invés da escrita de código - seja a meta do exercício. E quanto mais pessoas estiverem procurando por oportunidades de reutilização, mais provável será que elas sejam encontradas. Um brainstorming ou uma reunião de revisão, que se concentre na identificação de oportunidades de reutilização, pode ser útil para a consecução desta meta.

Os padrões são boas formas para encontrar oportunidades de reutilização no design e no framework.

A análise do comportamento é uma outra boa forma para identificar áreas potenciais para reutilização. Analise como as classes precisam colaborar para fornecer alguma funcionalidade específica, tal como um requisito ou característica. Esta colaboração pode ser documentada em diagramas de seqüência (comportamento) e classe (estrutura) e podem ser reutilizadas em circunstâncias semelhantes.

A Refatoração deve sempre ser considerada quando da reutilização de código. O código (ou o design) muitas vezes não é escrito originalmente para ser reutilizado, ou um código reutilizável pode não se ajustar perfeitamente a uma nova situação.

Técnicas de Reutilização

A reutilização pode ser executada de formas diferentes, dependendo da capacidade do ambiente de implementação. A técnica é mais simples é copiar o código de um lugar para outro. Isso não é aconselhável, pois não é realmente reutilização. Várias cópias de código fonte são difíceis de manter e eventualmente podem divergir umas das outras. A reutilização significa o uso do mesmo código para executar tarefas semelhantes, como forma de aumentar a qualidade e reduzir a sobrecarga.

Algumas linguagens, como o C++, suportam templates. Os Templates, às vezes referenciados como código parametrizado, são precursores dos padrões. Um template é um código com parâmetros que é aplicado apenas quando for necessário, em tempo de compilação. A Biblioteca Padrão de Templates (STL) do C++ é um exemplo. Ela fornece muitos tipos de contêineres reutilizáveis (listas, conjuntos, arrays seguros, etc) que não possuem alguns dos inconvenientes da herança. Os templates, tais como estes, também são úteis como classes de mixagem em linguagens como o C++ que suportam herança múltipla. Pelo fato das mixagens serem implementadas como templates, elas permitem um tipo de herança múltipla sem a bagagem.

Herança e Agregação

Herança (também conhecida como generalização) é uma forma fácil de implementar polimorfismo e tem sido usada como o principal mecanismo de reutilização nas modernas linguagens orientadas a objeto. Isso é lamentável, visto que a herança impõe uma estrutura rígida no design de software que é difícil de alterar. Qualquer hierarquia de herança que compartilhe código das classes pai para as classes filho terá problemas quando tiverem três ou mais níveis hierárquicos. Muitas exceções ocorrer para manter um puro relacionamento "é-um" entre classes pai e filho, onde se considera que as classes filho tenham sempre todas as propriedades e comportamentos dos pais. A herança deve ser usada para compartilhar definições (interfaces) e não implementações. Anos de dificuldades com implementações de herdando tornaram essa prática um princípio primário de design orientado a objeto.

Sempre que a herança for utilizada, é melhor ser instanciada apenas a última classe filho (nó folha) da hierarquia de herança. Todas as classes pai devem ser abstratas. Isso acontece porque a classe que tenta ser reutilizável e concreta - para fornecer comportamento específico e reutilizável ao mesmo tempo - quase sempre deixa de cumprir suas metas. Isto é uma dimensão da coesão. Uma coisa que torna uma classe coesa é que ela seja dedicada a reutilização ou dedicada a uma implementação específica, mas não a ambas.

A agregação é uma técnica que reúne ou agrega a funcionalidade em elementos maiores de funcionalidade. Ela fornece uma estrutura que é muito mais flexível e reutilizável do que a herança. É melhor reutilizar a implementação e o design agregando pequenos pedaços de funcionalidade em conjunto ao invés de tentar herdar a funcionalidade de uma classe pai.

Você também poderá encontrar oportunidades de reutilização, revisando as interfaces. Se as interfaces descreverem comportamento semelhante, pode ser possível eliminar uma das interfaces, tendo apenas uma implementação que realiza ambas as interfaces, ou re-fatorando as interfaces para colocar o conteúdo redundante em uma nova interface mais simples.

Encontrando Código Reutilizável

Existem várias fontes de código reutilizável sem ser o que os desenvolvedores estão escrevendo para um projeto específico. Outros locais para coleta de código são:

  • Bibliotecas internas (corporativas) de código.
  • Bibliotecas de terceiros
  • Bibliotecas embutidas nas linguagens
  • Exemplos de código extraídos de tutoriais, telas de ajuda, livros, etc.
  • Um guru local ou colega com bastante conhecimento de código
  • Código existente nos sistemas
  • Produtos de código aberto (tenha certeza de estar respeitando os acordos de licenciamento)

Também, muitas ferramentas capazes de gerar código poderão gerar código compreensível baseadas em especificações mínimas. Por exemplo, uma ferramenta de design poderia gerar um atributo com os métodos get e set assim que o Designer tivesse especificado-o. Outras ferramentas mais sofisticadas, com conhecimento de um framework específico, poderiam gerar código volumoso para garantir que a classe esteja em conformidade com o framework. Um exemplo poderia ser uma ferramenta que gerasse código adicional significante quando uma classe fosse definida como sendo uma entidade Java Bean. Este tipo de transformação consistente, de uma especificação (o design) para uma implementação (o código), pode também ser considerado uma forma de reutilização de código.

Não Reutilize Tudo

A reutilização torna o código e o design mais baratos de usar, porém mais caros para construir. Exige experiência e ponderada consideração para criar uma implementação ou design que seja suficientemente abstrato para que outros possam reutilizar, mas concretos o suficiente para serem verdadeiramente úteis. O código reutilizável também deve ser mantido. Muitas organizações terão dificuldade em atribuir responsabilidade para a manutenção de código reutilizável, se não tiverem um grupo dedicado a reutilização.

Normalmente não é uma boa idéia criar código ou design para reutilização, a menos que você saiba que ele será reutilizado. É melhor re-fatorar o software para ser mais reutilizável após ter sido descoberto que ele pode ser reutilizado. Uma regra de ouro é escrever pensando em reutilização só quando você souber que vai reutilizar o código pelo menos 3 vezes. Caso contrário, o custo de construção e manutenção de parte do software não será recuperado pela redução da sobrecarga em outras áreas de desenvolvimento.

Informações Adicionais