The Joys of Parameterization
We’ve all seen examples of parameterization. Database credentials are probably the most common example. Various scenarios may require that these be changed; a server move, a user/password change, or setting up a development environment. It’s easy to see how this is a best practice.
So, why stop there? It’s a verified best practice, why not apply it elsewhere as well? What circumstances might make something a candidate for parameterization?
I can think of a few…
Configuration values
As with a database, these can be resource credentials, but think also SMTP and API keys/URLs. Also consider values that can affect performance. Examples might be how many objects to process when a cron runs, or even how often a task should run. Any value that can help fine-tune performance can be parameterized to make it easy to adjust depending on the environment and server capabilities.
Semi-static Values
These are values that change once in a great while. Examples of this might be phone numbers, addresses, contact email addresses, tax rates, return day policy, etc.
Custom Deployment Configs
Sometimes you have an application that is used by different entities. The same codebase will be used by each entity, but must be customized to the specific needs of each.
Imagine if you have a web application designed to be used by schools. Each school will have unique parameters tailored to their situation. Any value that varies for each school should be a parameter. I had an interesting experience with a formula that needed to vary from school to school. I decided to parameterize every aspect of the formula for maximum flexibility. You can see the code and parameter design at the end of this post.
Parameter Format: File vs. Database
Most frameworks come with parameter files, but my favorite way to define parameters is in a database table. This has several advantages.The first is that a frontend interface can be created to manage parameters and values. This will be very convenient when it comes time to change a value, and your client will appreciate being able to set the value themselves, without having to rely on you.One of the most beneficial advantages is that you can track historic parameter values over time. To do so, use a schema such as:
[parameter]
id
name
[parameter_value]
id
parameter_id
value
effective_at
You can then grab a parameter value for a given date using a query like:
SELECT *
FROM parameter AS p
LEFT JOIN parameter_value AS pv ON pv.parameter_id = p.id
WHERE
parameter.name = ‘my_param_name’ AND
pv.effective_at <= ‘{$date}’
ORDER BY pv.effective_at DESC
LIMIT 1
Tax rates are a good example. Imagine a report that has a calculation that uses the sales tax rate. Now imagine the user wants to run that report for a date five years in the past. You’ll need the past sales tax rate to provide accurate results.
Example Case: parameterized formula
I’ll end this post with an examination of a real-world scenario I encountered. The end result was what actually inspired me to write this blog post, because I thought it was interesting how far one could take the use of parameterization. The scenario was that a codebase was used by different schools, and a formula within had to be different for each school. Usually a single value differs and is set via parameter. But in this case an entire formula had to vary by school.
Here is the original code for the formula:
$subCount = 0.05 * $studentCount;
if ($subCount > 30) {
$subCount = 30;
} elseif($subCount < 5) {
$subCount = 5;
}
You can see that the $subCount is first set to 5% of the $studentCount. Then a check is done to ensure the $subCount has a min and max between 5 and 30. Another school needed to always have the $subCount = 1. I could have just created a bool parameter for ‘always use 1’, but decided to make every aspect of the formula parameterized for maximum flexibility and future-proofing. Here is what I came up with:
dl_subcount_config: # minimum required for reporting
default: 1 # this is overridden if anything below is enabled
student_count_factor: { value: 0.05, enabled: false }
minimum: { value: 5, enabled: false }
maximum: { value: 30, enabled: false }
Note that the above is yml format, so indented lines fall under ‘dl_min_config’. When pulled in the code, the parameter is returned as an array within Symfony (our preferred framework for web applications).
Here is how I revised the code for the formula:
// get the parameter, which is an array defined in the yml
$sc_cfg = $this->getParameter('dl_subcount_config');
// first set $subCount to the default
$subCount = $sc_cfg['default'];
// now apply additional parameters only if they are enabled
if ($sc_cfg['student_count_factor']['enabled']) {
$subCount = ($sc_cfg['student_count_factor']['value'] * $studentCount);
}
if ($sc_cfg['minimum']['enabled'] && $subCount < $sc_cfg['minimum']['value']) {
$subCount = $sc_cfg['minimum']['value'];
}
if ($sc_cfg['maximum']['enabled'] && $subCount > $sc_cfg['maximum']['value']) {
$subCount = $sc_cfg['maximum']['value'];
}
You can see afterwards that every aspect of the formula now has a parameter. You can set a default and just use that if desired, or you can configure it to use a percentage of the student count, as well as a specified minimum and maximum range.
One of the key design elements here is that each parameter has an ‘enabled’ flag that determines if it should be applied to the formula. In this way, the formula can be modified in almost any way imaginable, all defined by parameters!
________________________ Endertech is a Los Angeles Software Development Company able to custom develop database applications. Contact us if you would like a free consultation.