Free tools Windows power users keep installed
One-click scans. No signup required.
A threshold that encodes a judgment about changing real-world behavior is a hypothesis, not a permanent invariant. Keep true constants—such as unit conversions or protocol-defined values—as constants. For heuristic thresholds, put related values in a configuration object with defaults matching the existing values, then inject that object into the code that uses it. You can make the values easier to revisit without changing the algorithm or its current behavior.
When is a threshold really a constant?
A constant is appropriate when a value is fixed by definition or contract: for example, a unit conversion or a protocol constant. A heuristic threshold is different. It represents an estimate about how the world behaves, based on observations and judgment that may need revisiting.
As an Amazon Associate I earn from qualifying purchases.
As Siddharth Pandalai puts it, “A threshold in a heuristic is a hypothesis about the world.” It may be informed and tested, but it is still a claim about observed behavior—not a rule that must remain true forever.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Why move heuristic values out of constants?
When changing a threshold requires editing code, review, a release, and rollout, the cost can discourage teams from measuring and revising it. Pandalai describes this problem in his own location pipeline: it had roughly eighteen such values, and shipping a change could take “a week at best.” Those are his account of that pipeline, not a general measurement of release timelines.
#1 Best Overall
His warning captures the risk: “If changing a number in your system requires a release, you will guess instead of measure.” The point is not that every threshold must be adjustable at runtime. It is that values representing revisable assumptions should be straightforward to find, understand, and change through an appropriate path.
Constants and injectable configuration compared
| Decision factor | Fixed constants | Injectable configuration |
|---|---|---|
| Best fit | A durable invariant, such as a unit conversion or protocol-defined value. | A revisable estimate used by a heuristic. |
| Changing a value | Usually requires changing code and shipping it. | The consuming component can receive a different value object; how that object is constructed or changed depends on the application. |
| Preserving current behavior | Existing value is embedded in the implementation. | Set configuration defaults to the existing values so the behavior remains the same until an override is supplied. |
| Required complexity | No configuration abstraction is needed for a genuine invariant. | A small data object is sufficient for ordinary grouped parameters; more machinery is justified only by requirements the object cannot meet. |
How to extract thresholds without changing behavior
1. Identify revisable assumptions
Find values that describe what the algorithm considers unusual, acceptable, too large, too fast, or too old. In Pandalai’s location-anomaly example, these include speed boundaries, jitter gates, history-window settings, a teleport gate, time-gap tiers, and a maximum gap distance. Keep protocol requirements and mathematical conversions separate when they are genuinely fixed.
Rank #2
2. Group related values in a configuration object
In Kotlin, the example uses a serializable AbnormalDetectionConfig data class for the related anomaly-detection values. Give each field a default equal to the value previously used by the implementation. The class’s DEFAULT instance is constructed from those field defaults, keeping the existing behavior unless a caller provides different settings.
@Serializable
data class AbnormalDetectionConfig(
// Declare the related thresholds and settings here,
// with defaults matching the former values.
) {
companion object {
val DEFAULT = AbnormalDetectionConfig()
}
}
class LocationProcessor(
private val config: AbnormalDetectionConfig = AbnormalDetectionConfig.DEFAULT
) {
// Use config fields in the existing processing logic.
}
The abbreviated declarations above show the shape, not the source article’s full field list or numeric values; the available description does not specify those numbers. The important compatibility check is that each default matches the old value exactly.
Rank #3
3. Inject the object into the consumer
Make the processor accept the configuration through its constructor, with the default instance as the default argument. Replace references to the old threshold constants with the corresponding configuration fields. The processing logic should depend on the values it receives, not on where the configuration object was created.
4. Verify the default path
Check that the defaults reproduce the old values and that existing processing behavior remains unchanged. Pandalai reports that his tests passed untouched after the extraction; that is his account of his implementation, not an independently verified result or a guarantee for other codebases.
Rank #4
Let the configuration source evolve separately
Once the processor depends only on a configuration object, the object’s construction point can change without redesigning the algorithm. A team might begin with the default instance, later provide overrides through debug settings, and eventually choose another construction mechanism if there is a concrete need. The processor does not need to know whether its values came from the defaults or an override.
Configuration can exist at different system boundaries. For example, Fuchsia’s platform guidance describes product and board configuration, schema-defined settings, and conditional feature inclusion. Android’s Settings documentation describes system settings for adjustable behavior, including thresholds and comma-delimited parameter groups. These are examples of broader platform mechanisms, not requirements for this Kotlin design.
Keep the abstraction proportional
A configuration object is a way to group values and separate them from the algorithm; it does not automatically make them remotely changeable or safe to modify without validation. Use the simplest source that meets the application’s actual needs. Pandalai explicitly cautions that this pattern is not a feature-flag system, rules engine, or remote code execution mechanism.
Quick Recap
- Keep true invariants as constants.
- Move related, revisable heuristic thresholds into a clearly named configuration object.
- Preserve behavior by giving the object defaults equal to the old values.
- Inject the object into the component that uses it, and keep that component independent of the object’s origin.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




