There is only one magic number in life, and that's 3. But in code magic numbers are those numbers that appear right in line and their origin is shrouded in mystery. Sure, some maybe obvious, like the maximum value of an int or the number of seconds in an hour, in the rest of the code context. Execute this loop 10 times or check that the value is less than 17 .... but why? Sometimes you need more context. I am fixing a bug, it seems like the bug is fixed if I increment this magic number but the original intent is not clear. I really love The Magic Numbers and their music, but in code they are easily mitigated. And while I am at it, let's talk about magic strings too. This was just one big ruse to talk about configuration.
The simplest thing you could do with a magic number is to make it a local constant because at least then you have to give it a name. So, could be the max, or min, for example and that can be incorporated into the name. We are off to a good start with at least that. In Java, these will be optimised at compile time and you could even make it a public constant, as many classes in the standard JDK have available. Other accessors are available.
If it's a public constant in Java then you can even just import that constant right into your code.
While I am saying this, I believe there are somethings that don't need to be a constant or some names that aren't really adding much value. For example, the empty string, probably doesn't need to be EMPTY_STRING="". Or the old classic public int static final ZERO= 0;
Show above as code examples.
Yes, I know I said use constants BUT I also said give me some context.
In some circumstances, the value is not set in stone. Maybe, we don't want to have to recompile our code or at least have to change the source code to change that value. I might even what to offer the user some flexibility. In that case, it might be an input parameter, to the API or method. So, this could be a little bit of per request config to brighten your users lives. An example of this could be the page size for a data query.
The constant may make more sense as a piece of configuration. It might provide a way to tune or tweak the system.
Helm.
In a multi-tenant SaaS or cloud service configuration at the tenant or user level in the form of a setting could be applicable. From starting at the magic number or string in your code, making it a setting exposed to the user could drive a better user experience. There is a scheduled task that runs every night at midnight for example, but you could also make that configurable for each tenant. Or you want to let your tenants define a specific password policy for the tenant users. There are a wealth of examples of user defined configuration and settings, so early thought should be given to this.
For internal config which is not changeable by your users, you will want to be able to change it without recompiling or needing to re-deploy. The service config in this case should always be externalised. Often the default value is enough, but you are least need the option to be able to set a new value quickly and efficiently. Whatever way you choose to do that, the system state should be reproducible in the case of a disaster, so design a process to change your external config to take that into consideration. If you change the external config and disaster strikes, all those little tweaks will be lost, so the process should be to have your changes in source control with the latest version available to be re-deployed if necessary. This should also be taken into consideration during service upgrades, as you don't want an upgrade to knock out some configuration changes you made before.
For this type of external config I would avoid this being per-tenant, as this adds an extra layer of complexity.
One well-used way to apply external config to your running service containers when using kubernetes as your orchestrator is through kubernetes config maps. This may mean restarting the service to pick up any new config.
Some of your configuration maybe connection and authentication credentials.
An alternative is to use a central config service, changes can then ripple through the system without the need to restart the servers. Not every project or system needs this, so careful consideration should be given as always before adding another layer of complexity or another part of your system that needs maintenance. Some frameworks may have centralised config built in or could look to building something bespoke with Apache Zookeeper for example.
From the simple little number inline in your code, to a centralised configuration service is a leap in system complexity but as a system grows in features and users the demand and necessity of such changes become realised. Your configuration, may range from a simple timeout value, to environmental configuration, to service connection and authentication. Abstract it, make it easy to update and keep it under source control where applicable but most importantly design it in.