Armadilhas para desenvolvedores: em busca do componente perdido

Texto escrito em 2012

O sonho de todo desenvolvedor é a componentização, mas a partir de algumas conversas das quais participo me pergunto: será que as pessoas realmente sabem do quê estão falando? Componentes aniquilam a repetição desnecessária, e  ingênuamente pensando, nada poderia dar errado, certo?

Definindo

Uma definição inicial de componente de software é: código que implementa determinada funcionalidade visando ser aplicado em diferentes contextos (sistemas) sem a necessidade de ser alterado. Lendo-a pela primeira vez temos a falsa impressão de que estamos lidando com algo razoavelmente simples de ser obtido. Sendo assim vou ir um pouco além expondo quais os atributos que um componente deve ter:

Estabilidade: o componente possui um comportamento que pode ser previsto por seus usuários. Para que isto ocorra faz-se necessário que seu código seja maduro e, de preferência, imutável, mas sim estendido por seus clientes (fechado para modificação, aberto para extensão). Só tem um problema: no universo tudo muda (certo Heráclito?).

Versionamento: a solução para o problema da mutabilidade é o versionamento. Tudo bem que os objetos se alterem com o tempo, mas em um momento específico estes estão em um estado acabado. O usuário de um componente para poder prever o seu comportamento precisa de um intervalo de versões. Por exemplo: sei que um certo recurso do MySQL possui determinado comportamento das versões 5.1 a 5.5.

Plugabilidade: o componente deve fornecer algum tipo de interface que possibilite sua interação com seus clientes e que explicite o quê pode fazer.

Essencialidade: o componente deve representar a essência da funcionalidade que implementa. Por exemplo: um banco de dados que só permita persistir e pesquisar informações médicas é um componente de uso bastante restrito. Em contrapartida um SGBD relacional já pode ser usado em inúmeras situações distintas. Problema: esta generalidade sozinha é inútil sem saber aonde pode ser aplicada.

Contextualidade: aonde o componente pode ser aplicado. Uma regra de negócio, por exemplo, pode ser vista como um componente dentro de um sistema mas será que tem uso fora deste? Normalmente não.

Isolabilidade: de nada adianta o nosso componente ser reaproveitável se não pudermos trata-lo de forma isolada. Este sempre deve poder ser substituído por outro (que vise o mesmo fim, lógico) de tal modo que seus clientes não precisem ser muito modificados neste processo. Traduzindo: um componente não pode aumentar o acoplamento nos sistemas que o usam. Um componente cujo código fonte foi alterado para um uso específico perde a sua capacidade de ser adotado em outras situações.

Como pode ser visto, um componente não é algo fácil de ser construído. Estamos lidando com uma criatura complexa e difícil de ser encontrada. É por isto que não me sinto à vontade quando vejo este conceito representado por metáforas visuais como peças de quebra-cabeça ou um mero cubo. Elas transmitem a idéia de que estamos lidando com algo simples o que não é o caso.

Componente é um software isolado e versionado que implemente a essência de uma funcionalidade e que possa ser reaplicado sem modificações em diferentes contextos.

Agora algumas armadilhas

Componentização prévia

É um erro muito comum em fábricas de software ou ambientes nos quais a pressão por alta produtividade esteja instalada. Os desenvolvedores são pressionados a escrever código que possa ser usado no maior número de situações possível. Problema: normalmente tentam criar o componente antes que uma segunda situação semelhante em que aquele código pudesse ser reaproveitado surja. Sabe, é importante lembrar um negócio aqui:

O reaproveitamento surge quando uma segunda, terceira ou enésima situação na qual uma mesma solução pudesse ser aplicada aparece.

Por via de regra, costumo pensar na possibilidade de criar um componente só a partir da terceira ocorrência. Dica: é muito raro sua lógica de negócio ter uso real fora do sistema em que surgiu. Normalmente os componentes mais bem sucedidos são aqueles que lidam com problemas mais básicos, como persistência, ordenação, elementos visuais ou outra funcionalidade cuja aplicação seja transversal dentro da sua empresa.

Dê a uma criança um martelo e o mundo se torna um prego

Há um detalhe muito pouco mencionado a respeito dos componentes. Como estes implementam a essencialidade de uma funcionalidade, em seu uso puro, como solução para o seu problema serão sempre o menor denominador comum. Não é raro em minhas consultorias chegar a empresas nas quais foi escolhido um componente que deva ser aplicado sempre que certo tipo de necessidade surja independente das suas características intrínsecas.

Um bom exemplo disto é a adoção indiscriminada de um SGBD específico. Será que sua empresa ao adotar apenas um SGBD consegue de forma produtiva e eficiente atender a todas as suas necessidades de persistência e pesquisa? Outro exemplo: será que usar apenas SOAP como estratégia de integração atende todas as suas necessidades?

Sim, é importante ter um componente padrão, mas melhor ainda é ter um leque de opções para a mesma categoria à qual o problema pertence. Só pode ter uma opção em sua empresa? Pelo menos escolha algo flexível ou fácilmente expansível (sinto cheiro de fanboy por aí).

Excesso de componentes levando a excesso de integrações

Componentes possuem uma verruga que se chama integração. Como na essência deste conceito está a isolabilidade, sempre que um componente é adotado, faz-se necessária a sua integração no sistema cliente.

Na maior parte dos casos a integração é via código mesmo: o componente é escrito na mesma linguagem ou já existe algum binding entre plataformas de desenvolvimento que permita seu uso de forma transparente. No entanto, nem sempre temos um mundo tão simpático assim. Lembre-se que em integrações nas quais é necessário executar transformações sempre há perda de performance.

Conclusões

Não me assustaria se algum leitor comentasse no blog que sou contra a componentização. Isto seria um erro: sou a favor do componente pensado e não naquele cuja origem foi forçada. Acredito que  devam surgir naturalmente a partir da experiência da empresa pois só assim conseguem de fato agregar algo à equipe.

É importante que o desenvolvedor tenha em mente os princípios que mencionei para que caso precise lidar com um gerente ou cliente mal informado lhe pressionando na execução desta "missão" possa expor as dificuldades inerentes ao problema e assim evitar ter mais retrabalho que reaproveitamento no final das contas.

20