And if you have multiple instances of your service running (e.g. regional endpoints), and you care about availability, then you'll be deploying sequentially to each endpoint and watching for anomalies before moving to the next endpoint.
There is still immense value in dynamic config in these scenarios.
100% agreed - but people miss that this applies just as much to deploying a "config change" as it does to a code change. Particularly if you're talking about feature flags, a config change and a code change are effectively equivalent - so you should apply the same standard to both. (What that standard should be is still a tradeoff)
> This is why one-box deployments and traffic shifting and feature flags exist (which are increasingly config-driven).
> And if you have multiple instances of your service running (e.g. regional endpoints), and you care about availability, then you'll be deploying sequentially to each endpoint and watching for anomalies before moving to the next endpoint.
I would agree that feature flags are config-like - and view them as the same antipattern. Traffic shifting and sequential deployment are great ideas, but they work great when deploying a code change. Make the change, gradually deploy the new version, roll back if needed. What does dynamic config gain you in that scenario? Only more possibilities to make mistakes, IME (e.g. the new version looked great on the "canary" node, but actually that instance had a different config from the other nodes).
A popular example: the Git client, which stores layered configuration files for repositories, users and installations including, for instance, local file names (such as diff tools) and user identities.
Git also serves as an example of how the line between configuration files and data can be blurred: it's customary to put in Git repositories .gitignore and other similar additional configuration files because it's useful and the software only cares about their presence, not their management.
That way when you have a customer whose antivirus is running on 8080, you can finally pull it out into config files, and you 'just' have to change the people who consume the constant to pull from config. Because you've already telegraphed the intent to do this.
A few jobs back I saw another side benefit to this: you can entice people to participate in improving the code. When code is really wrong people will ignore it. They can't be bothered to get invested in it. But when it's almost right they are often motivated to fix it the rest of the way. Either they see the potential and are inspired (new blood, trying to make their mark), or the unfulfilled potential grates on their sensibilities (crotchety veterans).
Source code is config which type-checks.
If you want to "reconfigure" your app while it's running, why not give it some input, rather than tracking down a textual yaml file and editing that.
I don't think anyone was implying having a config file obviated a program restart. I'd add that restarting an unchanged executable with an altered config file is going to be considerably faster than recompiling it.
> why not give it some input
If that's not a config file, then what are you suggesting?
Why should it be? We presumably have a VCS tag corresponding to the current version such that it would be very easy to check out the corresponding version and change only one file. Then an incremental rebuild with just that one file change should not take a significant amount of time. The business already needs to be able to fix code bugs quickly - hoping that any given issue could be resolved by a config change rather than a code change is not a sound strategy. So you need to have a process for deploying code fixes fast, and then you can just reuse that process.
For large systems compilation time is not actually the bottleneck for deploying a change - rather it's the testing (particularly integration testing). But actually a config change is just as dangerous as a code change, and the same level of testing is usually appropriate. In my experience many - perhaps most - production outages tend to be caused by "config changes".
> If that's not a config file, then what are you suggesting?
At some point an application does need to have dynamic behaviour in response to some form of input. But I'd argue that we're quite good at dealing with the things we see as first-class input - we know the importance of validating input before processing it, testing different input-handling code paths, and so on. "Config" tends to not be treated the same way - all too often the testers see it as part of the code and don't test config changes like other user input changes, but the coders don't test them like code changes either. It's a dangerous ambiguity; the system is made more robust by forcing everything to be one or the other.
> But actually a config change is just as dangerous as a code change, and the same level of testing is usually appropriate
Points well made, unarguably so
> In my experience many - perhaps most - production outages tend to be caused by "config changes".
I have no comparable experience but it sounds all too plausible and I shall bear that strongly in mind henceforth.
> "Config" tends to not be treated the same way [as code] [...]
From there to the end is brilliant. Thanks so much for such an excellent response. I'm going to print this out and keep it.
Source: decades of experience.
OK, let's try and interpret the parent post in a way that makes sense to me.
If your config data is effectively embedded in code and well isolated from the rest so that it could be extracted into an ini file easily, I'd buy that. I guess you lose flexibility as you have to recompile, but ok. Perhaps it's safer too.
> and [the code is] already using the best format you have for expressing your business domain logic
Well, often a good format for an abstract statement of actions is a list or grid of data which drives the code's decisions and actions. In that sense, if you've respected that, that's part of your config file (whether external, as a file, or embedded in the code though hopefully well isolated).
If none of this is your intention, could you let me know what you're thinking, with concrete examples please?
At every level of complexity, hard-coding a solution is the least evil option. Your codebase is a living expression of your business rules, and it's already using the best format you have for expressing your business domain logic (if this isn't true, use a better language). When the business rules change, the codebase should change. You already need to be able to deploy code changes quickly (e.g. to fix code bugs), so having to do a release/deploy to make a change to your business logic should not be a scary proposition; if it is, improve your release process.
Hard-code everything.