Passagens Aéreas e a Oferta Escassa

Já é bem conhecido o fato de que o preço de uma passagem aérea não tem relação nenhuma com o tamanho do percurso, e sim com a oferta e a demanda. Os preços das passagens são sugeridos por softwares complexos cujos objetivos principais são maximizar as receitas do vôo e minimizar a quantidade de assentos livres. O matemático Keith Devlin cita que há ainda os objetivos secundários de atrair usuários de outras companhias aéreas, e de criar lealdade entre aqueles que se utilizam frequentemente de serviços aéreos.

A partir das capacidades das aeronaves, quantidades de assentos de cada tipo, capacidades dos aeroportos destinados à companhia, dados históricos e sazonalidade, o software sugere preços dos bilhetes, tentando sempre maximizar a receita. Há também regras para estimular que os vôos sejam reservados com antecedência, permitindo melhor planejamento por parte da empresa aérea, e outras para estimular a utilização de dias e horários de baixos volumes, ou mesmo de aeroportos com maior capacidade ociosa. Há ainda regras que tentam identificar o cliente que está viajando a negócios e o cliente que viaja a passeio, para poder extrair o maior valor possível de cada público. O preço depende tanto desta logística complexa, e tão pouco da distância do trecho em si, que ocorrem casos onde é mais barato ir de São Paulo à Miami para depois voltar a Caracas, do que o vôo direto de São Paulo à capital Venezuelana.

Já que as companhias, os aeroportos e a própria malha aérea tem recursos limitados, a oferta de serviços aéreos como um todo é limitada. Se a oferta é limitada, priorizam-se os clientes mais rentáveis, em detrimento daqueles que não estão dispostos a pagar tanto quanto os primeiros. Em outras palavras, se houvesse recursos infinitos (aeroportos, aeronaves e espaço aéreo), a oferta aumentaria e os preços das passagens cairiam para valores mais próximos dos custos reais do serviço.

Este modelo de precificação, baseado na necessidade do cliente (e na oferta dos concorrentes) se opõe ao mais conhecido modelo de precificação por margem (markup), onde o preço é definido a partir dos custos (do produto ou serviço) somados a uma margem bruta de lucro. Os consumidores costumam ter a percepção de que o markup é um método mais “justo” de precificação, pois o preço fica intimamente ligado ao custo do produto/serviço, e não tanto à lei da oferta e demanda, tampouco ao quanto cada consumidor pode ou está disposto a pagar.

Software e o Custo Marginal Zero

Quando se fala em precificação de Software, a diferença principal é o custo marginal. O custo marginal de um software, seja ele disponibilizado na internet, ou mesmo gravado em CD, é infinitamente menor do que o custo de desenvolvimento deste. Temos então uma economia de escala, já que o aumento da produção (distribuição) fará o custo médio cair, à medida que os custos fixos são diluídos em grandes volumes.

Se desprezarmos os custos promocionais (e despesas de venda), e considerarmos um software sendo vendido em meio puramente eletrônico (ou seja, via download, que tem custo desprezível), qualquer preço acima de 1 R$ já é lucrativo. Milhares de pequenos fabricantes de software já comercializam seus softwares seguindo este modelo, cujo exemplo mais famoso dos últimos tempos é a Apple Store (iTunes Store), onde os usuários podem comprar diversos programas para o iPhone a preços que vão desde o gratúito até umas poucas dezenas de dólares, passando por toda gama de preços imagináveis.

Mas o fato de ter custo de distribuição desprezível significa que todo software deve ser comercializado por valores próximos do seu custo de distribuição? Obviamente não.

Preço Ótimo

Suponha que um determinado software possua a curva de demanda abaixo.

A curva exibe o número de clientes que comprariam o software para cada possível preço entre 50 e 400 R$. Suponha agora que o custo por cada unidade vendida é de 30 R$ (incluindo CD, manual, caixa, e correio). Vamos calcular os lucros para cada um dos possíveis preços:

Como se pode observar, os maiores lucros se dão com o preço de 150 R$.
Se a tabela acima for colocada em um gráfico comparando o preço de venda sugerido e o lucro total esperado (lucro unitário x quantidade esperada), podemos visualizar melhor que o valor ótimo é realmente próximo de 150 R$.

É comum que no processo de precificação que o empresário tente relacionar o preço ao valor investido no desenvolvimento do produto, mas isto é totalmente desnecessário. Segundo Joel Spolsky, o investimento que você fez no desenvolvimento do seu software é custo irrecuperável (sunk cost). A partir do produto pronto, você quer maximizar seus lucros, e este cálculo de maximização não depende do quanto você investiu no seu produto.

Na prática, não é tão fácil chegar ao preço ótimo. Não há como se estimar a curva de demanda, a não ser de maneira empírica, e para dificultar ainda mais, a curva de demanda pode nem ser decrescente, pois muitos consumidores ainda acreditam que a qualidade de um produto é diretamente proporcional ao seu preço (“you get what you pay for”). Tampouco é desejável fazer constantes ajustes nos preços para medir a curva de demanda.

Segundo Eric Sink, a melhor forma de definir o preço do seu software é pensar no seu posicionamento em relação aos seus concorrentes, e definir um preço que seja consistente com este posicionamento perante eles.

Segmentação

Em economia, o Excedente do Consumidor corresponde à diferença entre o valor que o consumidor estaria disposto a pagar por um bem e o valor que ele efetivamente paga.

Para que o empresário possa “capturar” este excedente, o que economicamente chama-se de “anular” o excedente do consumidor, pode-se recorrer a preços diferenciados ajustados à curva de procura. Ou seja, desenvolvem-se variações do produto, focando cada variação para determinado segmento, tentando extrair o máximo valor em cada segmento.

No mercado de software, esta segmentação tradicionalmente é feita através do desenvolvimento de uma versão completa, que depois é desmembrada para gerar versões simplificadas, com menos funcionalidades ou módulos.

É importante ter cuidado para não se criar um número muito grande de versões (segmentos), corendo o risco de confundir o consumidor. Eric Sink sugere que o software seja segmentado sempre em 3 camadas: 1) A camada mais inferior é a “Standard Edition,” oferecendo conjunto de funcionalidades muito básicas e um preço muito baixo; 2) A camada intermediária é a “Professional Edition,” feita para o maior segmento do seu mercado; 3) A camada superior é a “Enterprise Edition,” incluindo toda funcionalidade imaginável e precificada muito acima.

Para exemplificar o resultado financeiro da segmentação, vamos supor que no exemplo da sessão anterior o empresário ao invés de lançar seu software ao preço ótimo de 150 R$ (que lhe daria um lucro de 240.000 R$), resolva lançar 3 versões: a) Enterprise a 300 R$; b) Professional a 150 R$; c) Standard a 50 R$.
Supondo que cada consumidor adquira o produto na versão mais cara que ele está disposto a pagar, temos que:
a) Há 350 pessoas que pagariam até 300 R$, então comprariam a versão Enterprise por 300 R$.
b) Há 2000 pessoas que pagariam até 150 R$. Descontando as 350 pessoas anteriores (que compraram a versão Enterprise), sobram 1650 pessoas comprando a versão Professional por 150 R$.
c) Há 5000 pessoas que pagariam até 50 R$. Descontando as 2000 pessoas anteriores (que compraram a versão Enterprise ou a Professional), sobram 3000 pessoas comprando a versão Standard.

Temos então um lucro quase 47% maior do que teríamos com uma única versão (240.000 R$):

Para utilizar um exemplo real, podemos citar o Microsoft Office 2007. Sabemos que a maioria absoluta dos usuários deste programa só utiliza o Excel, Word, Outlook, e raramente o Powerpoint. Temos então a versão “Home and Student” que dos 4 programas citados só não possui o Outlook (que pode ser substituído pelo Outlook Express gratuito) e custa apenas 150 USD. Passando este segmento de entrada (versão Home and Student), todas as outras versões (Standard, Small Business, Professional e Ultimate) possuem os 4 aplicativos principais, e possuem preços variando entre 400 USD a 680 USD, variando em funcionalidades que são inúteis para a maioria absoluta dos usuários. No entanto, apesar de as versões serem quase idênticas, as empresas costumam comprar de acordo com seu porte e poder aquisitivo, aproximando-se inconscientemente da curva de demanda e reduzindo o excedente do consumidor.

O empresário e escritor Joel Spolsky critica o modelo de segmentação usado pela Oracle, SAP, e diversas outras start-ups inspiradas nos modelos deles, que fazem a segmentação através do modelo que ele chama de “Quanto dinheiro você têm?”. Joel explica que a Oracle não divulga preço de seus produtos em nenhum lugar, e que a única forma de obter preços é preencher formulário de contato, através do qual um vendedor faz contato com o cliente e tenta descobrir o quanto o cliente pode pagar. O autor explica que este modelo não só afugenta os compradores pequenos (que presumem que o preço é alto e não poderão pagar), como afugenta os compradores que não gostam de vendedores (fato já conhecido no segmento do varejo).

“Software as a Service” e o Preço Justo

O “Software as a Service” (SaaS) é basicamente uma nova forma de comercialização de software, onde o usuário não compra licenças sobre o software, mas sim as aluga. Tecnologicamente o SaaS é igual ao software tradicional, com a diferença de que normalmente o usuário não instala o software em seu próprio computador, executando-o diretamente dos servidores do fornecedor (através da internet).

Em sua forma mais comum, a cobrança de utilização de um serviço SaaS é feita por número de usuários e período de utilização. Para exemplificar, vamos supor que a Coca-Cola tenha 50 vendedores que se utilizam do software SalesForce, e paga 10 USD por cada usuário-mês. Ao longo de 1 ano, a Coca-Cola terá pago a SalesForce o valor de 6000 USD (12 meses * 50 funcionários * 10 USD).

Para efeito de comparação, caso a SalesForce vendesse licenças no modelo tradicional ao preço de 240 USD cada, a Coca-Cola teria comprado 50 licenças de utilização de seu software e teria pago o mesmo valor que ela paga em 24 meses no modelo SaaS (12.000 USD). Apesar de no modelo tradicional o cliente ter efetivamente propriedade sobre a licença (e o direito de continuar usando), ao final destes 24 meses o software adquirido pela Coca-Cola no modelo tradicional possivelmente já estaria defasado, caso a SalesForce tenha lançado uma versão mais nova. O cliente teria que decidir entre adquirir a nova versão do Software ou continuar com a versão antiga. Já no modelo do SaaS, as atualizações são sempre disponíveis, pois você está sempre pagando para ter direito de utilizar a “última versão”.

Uma vantagem óbvia para os clientes, é que o modelo SaaS é mais flexível à variações na demanda de utilização. Se, por exemplo, a Coca-Cola aumentasse o número de funcionários para atender uma demanda sazonal, bastaria pagar pelas licenças adicionais pelo período adicional, e ao término da demanda ela deixa de utilizar o software e deixa de pagar as licenças. Ou seja, o modelo é flexível, e os custos são diretamente proporcionais à utilização efetiva.

Mas as vantagens são ainda maiores. Conforme explicado anteriormente, o modelo clássico de precificação SaaS é cobrar por usuários e por período, no entanto, como o SaaS costuma ser gerenciado pelo próprio fornecedor, este têm um controle exato sobre o quanto e como o cliente está utilizando, e permite ao fornecedor calcular com precisão o quanto seu serviço é valioso para o cliente, e cobrar de acordo. Ou seja, o SaaS permite modelos de precificação mais elaborados, que consigam medir a real utilização do cliente, ou mesmo medir o quão valioso é o cliente, como por exemplo: cobrar um percentual sobre as vendas feitas através do software; cobrar de acordo com o giro do estoque; cobrar pelo número de telefonemas atendidos no call-center; cobrar de acordo com o número de funcionários para os quais o software está gerando a folha de pagamento; cobrar pelo número de emails enviados.

Para o cliente, o modelo de cobrança fica “justo”, e ele entende que a razão entre o benefício recebido e o valor cobrado é o mesmo para todos os outros clientes. Para o fornecedor, o modelo dispensa a necessidade de segmentar o produto (e consequentemente poupa esforço de estratégia de preços, posicionamento e promoção), pois permite ao fornecedor cobrar de acordo com o benefício recebido pelo cliente, e mais ainda, permite que o benefício recebido pelo cliente seja efetivamente benefício enxergado, pois o critério de cobrança é objetivo, tangível e mensurável. John Desmons aponta ainda que o fato do SaaS garantir receita recorrente é muito benéfico para ambos cliente e fornecedor, pois facilita previsão do fluxo de caixa.

Apesar de parecer inovador, o conceito de cobrar software e hardware de acordo com a utilização não é nenhuma novidade. Este modelo já tem sido usado há muitos anos pelos fabricantes de Mainframes como a IBM e a Unisys, que costumam emprestar seus supercomputadores para os clientes (como bancos), e cobram mensalmente de acordo com a utilização medida. Ou seja, a IBM empresta 6 ou 7 mainframes para Banco Itaú, mede mensalmente qual foi a utilização destas máquinas (em MIPS, milhões de instruções executadas), e envia a fatura. Se os mainframes estão com muita capacidade ociosa, a IBM leva embora alguns deles; se eles estão sobrecarregados, a IBM empresta mais máquinas para o Banco. Além do SaaS, a tecnologia de “Cloud Computing” também segue o mesmo modelo de precificação baseado em oferecer recursos ilimitados e cobrar de acordo com a utilização medida.

Conclusão

Voltando às passagens aéreas e ao custo marginal, se os aviões e vôos custassem poucos dólares e pudéssemos transportar número infinito de pessoas pelos ares, a precificação de passagens aérea seria exatamente como precificar software tradicional. Se além destas condições, a companhia aérea ainda pudesse identificar o quanto o vôo agregou para cada passageiro, identificando, por exemplo , quais dentre os executivos efetivamente fecharam bons negócios, ou quem sabe até identificar quanto dinheiro cada passageiro têm, e cobrar proporcionalmente com base nestes valores, neste caso estariamos precificando de forma tão justa quanto o SaaS.

Pagar por utilização de um software é como pagar pelos litros que você abasteceu no posto de gasolina, ou pelo peso da comida que você comeu no restaurante por kilo. É como pagar pelos minutos que você usou no seu celular, pagar tributos proporcionais à sua renda ou à sua movimentação financeira, ou pagar o boliche pelo tempo que você permaneceu jogando. É como sua conta de luz, sua conta de gás, e sua conta de água. É justo, consistente, e trata todos clientes como iguais. Definitivamente, o SaaS veio para revolucionar a forma como se comercializa software, e quem sabe até pra mudar toda a forma como os consumidores enxergam o conceito de “preço justo”.

Referências

1. Joel Spolsky: Camels and Rubber Duckies
2. Eric Sink: Product Pricing Primer
3. Keith Devlin: The crazy math of airline ticket pricing
4. John Desmons: [Software as a Service Gaining as a Pricing Model](http://www.softwaremag.com/L.cfm?Doc=1029-3/2007

Ungrounded Criticism

Frequently, when someone wants to criticize some source code, we usually hear complains about hardcoded stuff.
However, most of the time, hardcode is not a real problem, and more than acceptable, sometimes it’s even recommended.

Many developers completely misunderstand the hardcode problem, and make parametrized configurations of almost everything they can think of, and your program ends up as a bunch of unreadable code, completely driven by configurations that are rarely (if ever) changed. It’s not uncommon to see people who put all business rules into the database, and the program itself is just a interpreter which reads those rules - your database acts as a sourcecode, and your program acts as an interpreter (back into scripting days!) - completely nonsense.

I won’t discuss the definition of hardcode because it can be quite controversial. For this article you can consider that “hardcode” is when your data/rules are inside your sourcecode, and “parametrization” when they are outside your sourcecode.

So the main question is: What things can be hardcoded?

It’s pretty obvious that you should not hardcode things like database connection strings, or destination email addresses. But what makes those things different than acceptable hardcoded rules/data? To answer that question, you should first ask: Why avoid hardcode at all?

The answer to this question relies on software engineering. Not on code beauty, but on finances and on your development efforts:You should make parametrizations if it saves your money.

When you make something hardcoded, you spend X efforts, but in case you need to change it in the future you will spend W efforts.
When you make something parametrized, you spend additional efforts (X+Y), but in case you need to change it in the future you will spend less efforts (W-Z).
It’s a tradeoff: X is a little cheaper than X+Y during development phase, but if you need a change, maintainance W can be much more expensive than W-Z.
It’s exactly like refactoring: it costs you money, but you have a payback soon, because it makes your code more maintanable.

So which alternative will save your money? It depends on expected costs.

Expected Costs

Suppose you are throwing a dice, paying 2 USD for each throw, and winning 10 USD if you get a number one on dice. Should you play this game?
Expected prize is (16) * 10 USD = 1,66 USD. If you are paying 2 USD and you expect to win 1,66 USD, then you are loosing money.

It’s similar to PMBOK Risk Management formula: Risk Score = (Risk Probability) * (Risk Impact)

It works exactly the same in software engineering.

Back into Hardcoded

So should you have the additional effort Y of making something parametrizable? Depends on how much effort you expect to save in future maintainance.
If you expect a probability of change of P (in %), then the expected effort saving is P(Z-W). If Y < P(Z-W), you should make it parametrizable.
In other words, having something hardcoded costs you X in development, and an expected cost of change of PZ. By making the same thing parametrizable, it will cost you X+Y in development, and P(Z-W) in maintainance.

So the rule is: If parametrization efforts are cheaper than the expected saving in change efforts, parametrization should be done.

A few derived rules

We can conclude a few derived rules:

1) If something is very unlikely to be be changed in the future, probably you shouldn’t make it parametrizable.(I have seen it uncountable times)
Eg: Your ecommerce system applies taxes after discounts, but you have parametrized it so that if someday Federal Law changes, you’ll be able to apply taxes before discounts. How likely will it happen? Then why bother parametrizing?

2) If change efforts are insignificant, probably you shouldn’t make it parametrizable
Eg: You are developing a proof-of-concept, which will run only in your machine, will be compiled only by you, and will probably be trash in a few weeks. Why bother having parametrized DAL Factories for your database? I’m pretty sure that’s not what you are testing in your proof-of-concept, right?

3) If change efforts are cheaper than parametrization efforts, probably you shouldn’t make it parametrizable
Eg: ASP3 is not compiled, so changing sourcecode is trivial. Why would you bother parametrizing it in a structured XML file or Database when you can just have parametrizations as constant variables inside an INCLUDE.ASP file ?

4) If change efforts are similar with either parametrization or hardcode, parametrization can be esthetic, but it’s not really helpful.**Eg: Suppose you have a Build Server, completely configured with your Development, Test, Staging and Productions servers. Suppose you change sourcecode, click some buttons, and environments are updated. Why would you bother putting things into XML config files when changing XML file is as easy as changing directly source code? Use configuration wisely, but don’t be afraid to leave things inside your source code.

5) If data/rule “A” cannot be parametrizable (so it’s in sourcecode) and data/rule “B” cannot be changed without changing “A”, you should not make “B” parametrizable either.
Eg: If you have a workflow system, why would you define all your possible states inside a XML configuration file, if transition rules cannot be parametrized (at least not easily) in XML and therefore should reside in source code? In case you need to add a new state in XML, you would also have to program new rules in source code, so that’s double work to do.

Change Efforts Fixed Costs

Changing software usually involve fixed costs: where is source code? is it really the latest version? how to compile it? how to test it?
These costs vary from company to company, since each one has it’s own level of self-organization maturity, but as a general rule you should note that legacy software usually tends to be more obscure and will take you long time to understand/change/build.

Parametrization Costs

Having read previous parts, now I can tell you: parametrizing data is usually cheap, and parametrizing rules is usually expensive.
As a general rule, you can parametrize your data without fear, but you should really think carefully before parametrizing rules.
Remember also that rules can rarely (if ever) be changed only by changing configuration - usually you’ll need to change source code (see derived rule #5, above)

Additionally, you should note that having too many unecessary parametrizations can make your software confusing and unmaintainable.

Parametrization Guideliness

1) Web.Configs (and App.configs) are just for that. You don’t have to reinvent the square wheel. You can put connection strings there without fear: those files are exactly for this.

2) Serialization can be a pain in the ass. Keep your parametrizations as simple as possible, don’t try to make complex serialization rules, or use complex design patterns, in something that should be rather simple.

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.

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.