Quando Hardcode é Aceitável

Críticas sem Fundamento

Frequentemente, quando alguém quer criticar um código fonte, geralmente ouvimos reclamações sobre trechos hardcoded.
No entanto, na maior parte das vezes, hardcode não é verdadeiramente um problema, e mais do que aceitável, em alguns casos é até desejável.

Muitos desenvolvedores compreendem errado o problema do hardcode, e fazem configurações parametrizáveis de quase tudo que podem imaginar, de modo que o programa se torna um montão código ilegível, completamente comandado por configurações que raramente (ou nunca) mudam. Não é incomum ver outros que colocam todas as regras de negócio dentro do banco de dados, e o programa em si vira meramente um interpretador que lê estas regras - seu banco de dados funciona como código fonte, e seu programa age como um interpretador (de volta à era dos scripts) - completamente sem sentido.

Não vou discutir a definição de hardcode pois esta discussão poderia se tornar extremamente controversa. Para este artigo você pode considerar que “hardcode” é quando seus dados/regras estão no código fonte, e “parametrização” quando eles estão fora do seu código fonte.

E a questão principal é: Quais coisas podem ser hardcoded?

É bem óbvio que você não deve tornar hardcode coisas como strings de conexão com o banco de dados, ou endereços de destinatários de email. Mas o que torna estas coisas diferente de outras regras/dados que são aceitáveis de serem hardcoded? Para responder esta questão, você primeiro deve perguntar: Por quê afinal devemos evitar hardcode?

A resposta à esta pergunta está na engenharia de software. Não em padrões de código, mas sim nas finanças e nos esforços de desenvolvimento:Você deve fazer parametrizável se isto for economizar seu dinheiro.

Quando você faz algo hardcoded, você gasta esforços X, mas caso você precise mudá-lo no futuro irá gastar esforços W.
Quando você faz algo parametrizável, você gasta esforços adicionais (X+Y), mas caso precise mudá-lo no futuro irá gastar menos esforços (W-Z).
É um trade-off: X é um pouco mais barato do que X+Y durante a fase de desenvolvimento, mas caso você precise de uma mudança, a manutenção W pode ser muito mais cara do que W-Z.
É exatamente como o processo de refactoring: custa dinheiro, mas você tem um payback rapidamente, pois ele torna o seu código mais fácil de dar manutenção.

Então qual alternativa vai economizar seu dinheiro? Isso depende dos custos esperados.

Custos Esperados

Suponha que você esteja participando de um jogo de azar. Você está pagando 2 R$ por cada jogada, joga um dado (6 faces) e recebe 10 R$ se o dado cair na face 1. Você deve entrar neste jogo?
O prêmio esperado é (16) * 10 R$ = 1,66 R$. Se você está pagando 2 R$ por jogada e espera ganhar um prêmio de 1,66 R$, então você está perdendo dinheiro.

É similar à fórmula de Risk Management do PMBOK: Risk Score = (Risk Probability) * (Risk Impact). Se a probabilidade é baixa, mesmo que o impacto seja alto o risco se torna menos relevante.

Funciona exatamente assim na engenharia de software.

De volta ao hardcode

Então você deve despender o esforço adicional Y para tornar algo parametrizável? Depende de quanto esforço você espera economizar em manutenções futuras.
Se você espera uma probabilidade de mudança de P (em %), então o esforço economizado esperado é P(Z-W). Se Y < P(Z-W), você deve fazê-lo parametrizável.
Em outras palavras, ter algo hardcoded te custa X durante o desenvolvimento, e o custo de mudança esperado é PZ. Ao fazer com que isto seja parametrizável, vai te custar X+Y no desenvolvimento, e P(Z-W) na manutenção.

Então a regra é: Se os esforços de parametrização são menores do que o esforço que você espera economizar nas alterações futuras, a parametrização deve ser feita.

Algumas regras derivadas

Podemos concluir algumas regras a partir da regra anterior:

1) Se algo é improvável de ser alterado no futuro, provavelmente não deve ser parametrizável.(Já vi este erro incontáveis vezes)
Ex: Seu e-commerce aplica os impostos após os discontos, mas você parametrizou para que caso algum dia a legislação mude, você possa mudar a parametrização e aplicar os descontos antes dos impostos. Quão provável que isto realmente aconteça? Então por quê se preocupar em parametrizar?

2) Se os esforços de mudança são insignificantes, provavelmente não deve ser parametrizável
Ex: Você está desenvolvendo uma prova-de-conceito, que só será executada em sua máquina, só será compilada por você, e provavelmente será lixo daqui a alguns dias. Por quê você se preocuparia em fazer DAL Factories parametrizáveis para o seu banco de dados? Tenho certeza que não é isso (DAL Factories) que você está testando em sua prova-de-conceito, né?

3) Se os esforços de mudança são mais baratos do que os esforços de parametrização, provavelmente não deve ser parametrizável
Ex: ASP3 não é compilado, então alterar o código fonte é trivial. Por quê você se preocuparia em parametrizar configurações em um XML estruturado, ou banco de dados, quando você pode simplesmente ter as parametrizações como constantes dentro de um arquivo INCLUDE.ASP ?

4) Se os esforços de mudança são similares tanto com parametrização quanto com hardcode, a parametrização pode até ser estética, mas não é útil.
Ex: Suponha que você possua um Build Server, totalmente configurado com seus ambientes de Desenvolvimento, Testes, Homologação,e Produção. Suponha que você altere o código fonte, clique alguns botões, e os ambientes são atualizados automaticamente. Por quê você se preocuparia em colocar coisas em arquivos Config XML já que alterar estes arquivos XML é tão fácil quanto mudar diretamente no código fonte? Use arquivos de configuração inteligentemente, mas não tenha medo de deixar coisas no código fonte.

5) Se um dado/regra “A” não pode ser parametrizável (então está no código-fonte) e um dado/regra “B” não pode ser modificado sem modificar “A”, então “B” também não deve ser parametrizável.
Ex: Você tem um sistema de workflow. Por quê você definiria todos os possíveis estados dentro de um XML de configuração, já que as regras de transição não poderão ser parametrizáveis no XML (pelo menos não fácilmente) e dese modo terão que ficar no código-fonte? Caso você precise adicionar um novo estado no XML, necessariamente você também teria que adicionar novas regras no código-fonte, então seria trabalho em dobro.

Custos Fixos dos Esforços de Mudança

Alterações no software normalmente envolvem custos fixos: aonde está o código fonte? este é realmente a última versão? como compilá-lo? como testá-lo?
Estes custos variam de empresa para empresa, já que cada empresa tem seu próprio grau de organização e maturidade, mas como regra geral você deve se lembrar que software legado (especialmente aquele que não tem alguém constantemente mexendo) tende a ser mais obscuro e vai te tomar mais tempo para entender/modificar/compilar.

Custos de Parametrização

Agora que você já leu até aqui, já posso te dizer: parametrizar dados geralmente é barato, e parametrizar regras geralmente é caro.
Como regra geral, você pode parametrizar seus dados sem medo, mas você deve pensar cuidadosamente antes de parametrizar regras.
Lembre-se também que regras raramente (ou nunca) poderão ser modificadas apenas modificando arquivos de configuração - normalmente você precisará mexer em código fonte (veja a regra derivada #5, mais acima)

Além disso, você deve observar que ter um excesso de parametrizações desnecessárias pode tornar seu software confuso e impossível de mexer.

Orientações para Parametrização

1) Web.Configs (e App.configs) são exatamente para isso. Você não precisa reinventar a roda quadrada. Pode colocar suas strings de conexão lá sem medo: estes arquivos são exatamente para isso.

2) Serialização pode ser um pé no saco.. Mantenha suas parametrizações o mais simples possíveis - não tente criar regras de serialização complexas, ou usar design patterns complexos, em algo que deveria ser realmente simples.

Example

Suppose you have an application which sends periodic emails to Bill from the accounting department. You can hardcode “[email protected]” into your program, or you can put it into some configuration file (or database) and name it as “AccountantEmail”. Hardcoding would take you 1 minute. Putting into configuration file would take no more than 1 additional minute.
It’s tempting to think of it as being a quite huge additional 100% effort, or as being a quite small effort (1 minute), but that’s not the correct way of thinking - you should think in terms of payback.

Let’s analyse the estimated effort.

Suppose that your company has merged with another one, and Bill is not your main accountant now. By the moment someone’s need to change this rule/data, two things may happen:

1) The guy who will change this destination email address does not know anything about the system you have designed/developed.
He barely knows where the system resides. He will have to find out where are your sources, try to find where in source code is that email address, and proceed with the change.
He may not even have the appropriate IDE to recompile your application. He may not be able to recompile (where are the dll references?), or may be unsure about how to recompile it.
Let’s suppose that no tests are necessary, and let’s ignore the fact that after changing and recompiling a change request should be prepared (since in both cases he does not have access to production environment).
Taking all that real word facts into account, in the best case this guy will took 20 minutes to get code, change, recompile, and put into production.

2) The guy who will change this destination email address does now know anything about the system you have designed/developed.
He just asks for a copy of application’s configuration file, finds out that there is a tag called “AccountantEmail” pointing to Bill’s email address, and changes this tag.
In worst case, that would take 10 minutes.

Suppose now that your system has an expected life of 3 years, and during this lifetime you estimate that there is a 50% probability of changing this rule/data (destination email address) at least once.
By making the rule hardcoded during development phase would take you 1 minute, and there is a 50% chance of needing to change it (which would 20 minutes), so inicial efforts and estimated change efforts are 1 minute + 50% * 20 minutes = 11 minutes total.
By making the rule parametrized during development phase would take you 2 minutes, and there is a 50% chance of needing to change it (which would take 10 minutes), so initial efforts and estimated change efforts are 2 minutes + 50% * 10 minutes = 7 minutes total.

Therefore, this email address should be parametrized.

comments powered by Disqus