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.
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 (1/6) * 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 P*Z. 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.
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.
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.
Suppose you have an application which sends periodic emails to Bill from the accounting department. You can hardcode "firstname.lastname@example.org" 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.