Make hard coding your default choice

By Vladimir Khorikov

Hard coding is often considered an anti-pattern. Having values that can change over time hard-coded in the source code requires recompilation every time these values actually change.

While this statement is true, I think that hard coding should be the default choice when developing an application.

Hard coding vs configuration file

When you work on a project or feature, there always are some magic numbers or strings that potentially can change in future. The first impulse is to make such changes configurable so that you could easily modify them later.

In most cases, such decisions complicate further maintainability. What we have here is a classic dilemma “simplicity vs agility”. As the application grows, it becomes easier to change some of its parameters because they are extracted to the configuration file, but at the same time the overall burden of maintenance increases.

In an extreme case, you might end up having tens or even hundreds of configurable parameters, which make it utterly hard to maintain the application. Such situation is called configuration hell.

Just as with many other software design decisions, we need to appeal to the YAGNI principle. Do all these parameters really need to be configurable right now? Or do we just make some up-front arrangement? If the latter is the case, we are better off cutting the configuration file and keeping it small up to the moment when the need for it becomes apparent.

Hard coding should be the default choice unless the necessity for the otherwise is proved. By hard coding, I don’t mean you should spread magic numbers and strings across your project’s source code. They still need to be gathered and put in a single place as constants. Yet, that means you should remove them from the config file.

Logging example

Let’s take some example and see how we could apply what was said above in practice.

My favourite logging library is NLog. It has a tremendous amount of features, each of which is easily configurable.

Here’s a configuration file for a typical NLog setup:

<nlog>

  <variable name=logFile value=C:\logs\log-${shortdate}.txt/>

 

  <targets>

    <target name=trace xsi:type=AsyncWrapper queueLimit=5000 overflowAction=Block>

      <target name=file xsi:type=File encoding=utf-8

              layout=Date: ${longdate}\r\n Level: ${level}\r\n Message: ${message}\r\n

              fileName=${logFile}.txt

              archiveFileName=${logFile}.{#####}.txt

              archiveAboveSize=2097152

              maxArchiveFiles=200

              archiveNumbering=Sequence/>

    </target>

  </targets>

 

  <rules>

    <logger name=* minlevel=Warn writeTo=trace/>

  </rules>

</nlog>

While the setup itself is quite reasonable, I’d like to raise a question: is it really necessary to keep all these settings in the config file? Are we going to change them? In most cases, the answer is no. Even if you are doubtful of it, that also means “no” due to the YAGNI principle.

Luckily, NLog allows us to use its Configuration API in order to configure it in code. So, instead of counting on the config file, we can easily move the settings to the source code. Let’s take a closer look at the example and see which of the settings we can get rid of.

First of all, you can see in the targets section that we use an async wrapper for the actual target. Do we really want it to be configurable? No, such setting barely ever gets changed. Okay, what about the other target? It sets a lot of useful things, e.g. log entry’s layout, file name, maximum log file size and so on. Do we really need to have an opportunity to change them without recompilation? Most likely, no.

What about the rules? This part is not as obvious as the one with targets. The possibility to change the minimum log level required to trigger the rule seems sensible because we might want to adjust it on the fly for debugging reasons. Nevertheless, odds are we never appeal to it in practice. So, we are better off removing this setting as well.

Alright, what we have ended up with? Only a single setting is left, which is the path to the log file itself:

<appSettings>

  <add key=LogFilePath value=C:\logs\log-${shortdate}.txt />

</appSettings>

All the other settings now reside in the source code:

string layout = “Date: ${longdate}\r\n +

    “Level: ${level}\r\n +

    “Message: ${message}\r\n;

 

var config = new LoggingConfiguration();

 

var target = new FileTarget { FileName = fileName, Layout = layout /* Other params */ };

var asyncWrapper = new AsyncTargetWrapper(target)

{

    QueueLimit = 5000,

    OverflowAction = AsyncTargetWrapperOverflowAction.Block

};

var rule = new LoggingRule(“*”, LogLevel.Error, asyncWrapper);

config.AddTarget(“asyncWrapper”, asyncWrapper);

config.LoggingRules.Add(rule);

 

LogManager.Configuration = config;

As you can see, we removed the nlog section completely and moved the remaining setting to the appSettings section. It is now an ordinary member of our configuration file.

This single setting is the only one that really needs to have different values depending on the environment being used in. What we did here is we reduced the configuration surface and thus made the solution more maintainable at the cost of making it less flexible. And I strongly believe this is a good trade-off.

Later on, we might find ourselves changing one of the hard coded settings too often. That would signalize we do have a good reason to move it to the configuration file. But up to this point, just make hard coding your default choice.

Summary

I apply this rule regularly to all of the settings that could potentially be moved to configuration files. It helps keep them small and maintainable. Also, I noticed that even if I occasionally need to change one of such settings, making the change directly in the source code is sufficient in most cases.

Update

I need to note that the content of the article is applicable to in-house software only. 3rd party library development is a different story.

Also, I really appreciate all the feedback I got on that topic, I didn’t expect there would be so much of discussion here. But please, don’t confuse the main point of the article – which is making hard coding your default choice – with making hard coding the only choice. If you do need to extract some values out of the code and make them configurable – you are good to do it. The only thing I advocate you do is asking yourself whether such extraction is really needed.





  • lalaland

    Should not hard coding be “hardcoding” a one word ?

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Good question 🙂
      Wikipedia says it can be either way: http://en.wikipedia.org/wiki/Hard_coding

      • lalaland

        When this appeared in my RSS I thought this is going to be about “hard core” coding …kind of ASM, C, Haskell or something very low level lol 🙂

    • Arunkumar S Jadhav

      Indeed! I read it as “make coding hard your default choice” 😉

  • Richard Bucker

    immutable configuration is a great way to deploy a resilient production environment… especially with CI/CD.

  • http://www.facebook.com/emsternberg E. Mathieu Sternberg

    It occurs to me that “hard coding” is the default starting pattern of all TDD: “Make the code return this value. Now extend (substitute variable for constant; substitute collection for variable, etc…).” Maybe “move to a configuration file” is a YAGNI issue.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Yeah, it is a YAGNI issue.
      “Only create code you need right now” can be applied to configuration files as well 🙂

  • solipsistnation

    How about hard-coding the default but letting users override it in a config file which is documented, so that when somebody _does_ want to change it, they can go do it without poking around the source? That way your config file only includes the things that have been changed from default, so it stays readable.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      I’d say it’s a good approach. I personally strictly follow Yagni, and not introduce even possibility to setup values via the config file until I really need to, but your solution is a good “in between” approach.
      Also, the article’s content is related to in-house development only, i.e. when you have a full control over the deployment process. If you develop a 3rd party library, then you do need to introduce configuration opportunity up-front. In this case, the approach you described I think is the most viable.

      • Jas Atwal

        You can get this for free by using the settings file in VS.

  • Mathew Bollington

    This is a fair observation. The majority of configuration parameters I’ve worked with, or created, hardly ever change at all. Even collecting into a single location in the code base might be an unnecessary level of complexity depending on your development environment.

    It’s a shame that the relative costs of rebuild & deployment vs implementing and testing (configuration parameters) cannot be properly quantified, let alone predicted; that’s the real nut to crack.

    This says nothing about the difference between internal parameters created for ease of maintenance and customer parameters that are requested as part of the requirements.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      >This says nothing about the difference between internal parameters created for ease of maintenance and customer parameters that are requested as part of the requirements

      You are right. In the case when the parameters are requested by requirements, I think there’s no other choice but to add them. Nevertheless, it’s still worth arguing with your product owner if you see that some parameters are being added just for the sake of creating configuration settings.

      Also, there’s a difference between in-house software development and 3rd party library development. If the latter is the case, you do need to introduce some configuration settings up-front. I posted on that topic here: http://enterprisecraftsmanship.com/2015/02/08/shared-library-vs-enterprise-development/

  • Jeff O

    I would suggest all-or-nothing on the config file.Putting setting in two place just because some are more likely to change than others, doesn’t simplify it for me.

  • Caio Souza

    I think this article is misleading.
    There is a huge difference between constants/parameters who go to into code files, and configurations who goes to config files, none of them are hardcoded.
    Not being able to differentiate what is a “project configuration variables”, and what is a “code constants/parameters” is the first error.

    handling both as the same thing will make many ppl make wrong design choices and really hardcoding.

    No project with more than 1 people working on should have hardcoded things.

    • MagicBishop

      “No project with more than 1 people working on should have hardcoded things” . You must not work very close to the metal. Our drivers and firmware are full of hardcoded constants. The more setting access you give to customers the more they F stuff up.

      • Caio Souza

        Well, my intention was to talk about large projects with some high level of abstraction where many people work/ make changes in the same thing.
        Close to the metal most of the things are too specific and have no abstraction( not like the one I meant in the other paragraph). Then, yes it is better to be a “black box” since you really don’t want other ppl messing with it.
        Even in this case you must be able to differentiate what is a project config and what is a code const/param.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Well, the thing is, when you work on an in-house software, there’s efficiently no difference in “project configuration variables” and “code constants/parameters”. Deployment of a new version of the application after changing a hard-coded parameter takes as much time as changing a config file. At the same time, maintenance costs for hard-coded values are lower.

      > “No project with more than 1 people working on should have hardcoded things.”
      Such attitude often leads to configuration hell – a situation I argue against in the article.

  • mongonv

    The concept of putting your configurations in the code may be OK if you have ONE installation of an application and ONE developer. We have a number of applications that are deployed to multiple sites and need configurations that are different at each site.

    Putting those configurations in the code is a very bad idea and frankly kinda shocked that it is being suggested. Creating simple libs that are used to retrieve params from a central / standard location is far more flexible and easy to maintain than having to hunt thru code to figure out where some other developer decided to hide a configuration parameter or having to update the code to deploy to a new location.

    We put all our params in a database table or the server context so that we can deploy the app, set the params for the site and it runs and redeploys work without having to make site specific changes to the code. In the code anything that is a site configurable parameter all gets retrieved through one mechanism, so its use is very easy to use in the code and very easy to update.

  • http://www.opwernby.com/ Dan Sutton

    It depends partially upon what you use to write the application. If you’re doing it something like PHP or ASP.Net, then (unless, in the latter case, you’re relying on compiled DLLs rather than letting the web server compile on the fly) you can go changing the source code any time you like, in place, to modify configuration settings. Of course, if you have something like a source control system, then this plays hell with whatever your base code library looks like… but at least you don’t have to recompile the whole thing and then redistribute it.

    If you’ve got, say, a compiled WinForms application, though, you have no choice but to use a config file (or the Windows Registry) – what are you going to do: hack the binary to change the configuration?

    But the main attraction of having a configuration file is to keep all your settings in one place: everyone knows where they are, everyone can change them, and nobody has to go poring through loads of code to figure out how to do it.

    Unless you’re the only person who’s ever going to maintain the application, a configuration file is the way to go. If you like, you can always load it up into a set of static variables once the application starts, then it’s in memory and you get your speed advantage at that point… but a configuration external to the code itself is a must.

  • Brandon Wilhite

    I generally agree. I think the question you have to ask yourself/product owner is “How often is this likely to change?” Depending on how often it may change is when you start considering to move your configuration out of code. With very greenfield work (not a rewrite, let’s say, but a new thing altogether) you are unlikely to be able to answer this question…YAGNI kicks in and so default is to avoid the complexity. The same consideration also applies to lookup data, imo.

  • David Griffin

    I’d have said that “who’s going to be changing the values” and “where from” also determines whether it’s in a runtime text file or a part of the source, Noone but the developer should be recompiling the app if it’s just to change a variable that was always anticipated could change. Similarly, a webapp may only need reconfiguring by changing a text file and restarting. or it may need a web interface to change the config because the person changing itr is not going to be given file access to the server.

    A key consideration with config files is all the error checking. At least with a hard coded file a stupid value can fire an assertion at compile&test time. With a runtime config you have to gracefully handle whatever someone else can throw at you, unless you have a policy of replacing any daft values with better defaults, but multiple values that are individually OK can cause a bad combination, so knowing which to overrule is non trivial. Handling stuff may be fine in an app with a UI, less so in environments running mostly unattended.

    If the author is really saying “expose the minimum possible damage potential to non developers” then I guess I’d go along with that.

  • Leonardo Lazcano

    I have suffered the “configuration hell” in many in house systems, also suffered the “hard coded hell” in some others, i propose you make all those variables configurables, but you can hard code default values for them when they are not on config files, so you don’t need to have large config files, unless its required.

  • http://gettingsharper.de/ Carsten König

    while this might be true for some parameters there are still lot’s of things in In-House software (my day-job) that calls for config files: you will hate yourself (or your peer) for those hard-coded connection strings and file-paths once (after a few years) your IT decides to finally buy a new database-server, move those files, reorganize the network or just if you decide to port your software to a different site – I honestly don’t want to compile my software for each machine I’ll run it on …

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Well, I definitely wouldn’t suggest moving connection string to the source code. That’s the parameter that is clearly needs to be configured in the config file.

  • Dissimulus Umbriel

    I’d argue that since the definition of ‘hardcoding’ depends on the programmer, what you’re doing might not be hardcoding at all. Most people I know consider putting magic values inline in your code is ‘hardcoding’, but once those values get put together in one place with clearly defined variable names, they stop being ‘hardcoded’, even if they’re constants (so semantically speaking, they’re hardcoded constants, yet some people don’t consider them as such).

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      Yeah, I agree there’s a bit of inconsistency in the definition of this term. I personally consider “hard coding” putting parameters in source code regardless of whether or not they have clearly defined names. Here’s what Wiki says on that topic ( https://en.wikipedia.org/wiki/Hard_coding ):

      Hard coding (also, hard-coding or hardcoding) refers to the software development practice of embedding what may, perhaps only in retrospect, be considered an input or configuration data directly into the source code of a program or other executable object, or fixed formatting of the data, instead of obtaining that data from external sources or generating data or formatting in the program itself with the given input.

      • Dissimulus Umbriel

        Indeed. However, you might want to refer to Wikipedia’s definition in your article. A simple link would do. Less ambiguity leaves less chances for misunderstanding.

        On a more personal note, I’d leave the level and log size in the config. But that’s just me. 🙂

        • http://enterprisecraftsmanship.com/ Vladimir Khorikov

          You are right. Updated the article with a link to Wiki, thank you 🙂

  • http://gatesvp.blogspot.com Gaëtan Voyer-Perrault

    I think your example is a complete failure.

    The title of this blog is “Enterprise Craftsmanship”, which implies that you’re building things on a large scale with multiple developers, a QA team and more than one environment.

    And if that’s the case, your hard-coding of logging variables is wrong. These _should_ be different in every environment. The default logging settings for a developer’s machine should be very different from the Production settings.

    – Log levels should be different, you don’t want to run Production at DEBUG level, but your development box probably does run at DEBUG.
    – Logging file locations are probably going to be different because of the User security context on the Production servers.
    – File sizes that make sense on an development laptop, probably don’t make sense on a Production server.

    You claim YAGNI many times, but clearly you _are_ going to need it. You can keep a hard-coded default, but the _least_ you should do is accept a config file override.

    • http://enterprisecraftsmanship.com/ Vladimir Khorikov

      The thing is, you can’t know for sure whether or not you really need them until you deploy it in production. Also, the example doesn’t state you can’t ever move the log level or the file size to the config file (note that the log file location is already there). It only advocates you create them in code by default. You can always move them to the config file later when you face the necessity of it in reality.

      Often config file is considered a rigid structure we need to design up-front. I strongly believe we need to apply the same principles and practices to them as we apply to source code. That is, we need to keep it as simple as possible and only extend when we really need it.

      • http://gatesvp.blogspot.com Gaëtan Voyer-Perrault

        “The thing is, you can’t know for sure whether or not you really need them until you deploy it in production.”

        Yes you do… I can tell you right now, you want different log configurations in Dev & Production. Unless you don’t have an Ops or Compliance team that cares about this stuff… but what type of Enterprise software are you building that doesn’t have one of those?

        • http://enterprisecraftsmanship.com/ Vladimir Khorikov

          >”I can tell you right now, you want different log configurations in Dev & Production.”
          In this case, you are good to extract it to the config file. Remember, the whole point of the article is not that you can’t do it. It’s that you have to be very sure you need it before putting it there.

  • Desire Inspires

    I don’t see the huge divide between “programming” and “computing” that others see. Of course, the student programming that I see is all problem solving, not rote exercises. Students can fail at the programming in many different ways (poorly chosen data structures, poorly chosen program organization, poorly chosen algorithms, incorrect coding of algorithms, bad documentation, non-idiomatic use of the programming language, …). I see very high correlations between these different failure modes—I don’t have large enough samples to do factor analysis, but I suspect that I would see primarily one factor for programming skill, with a minor second factor for completeness of documentation. I doubt very much that I’d be able to associate one factor with “programming” and another with “computing”.