Naming should be consistent with today’s context – not yesterday’s or yesteryear’s.
The function extraction refactor is a great opportunity to refine naming. Usually we’re extracting a function because we intend re-use or a function has grown too complex. For example, we might have several cases of data with special math for each.
For re-use, we’re providing an interface in the context of, well, whoever can call the function. Future readers won’t know about the original function. When simplifying functions into subroutines, we’re implicitly creating a future interface…!
In any case, we are changing code from one context to another. Let’s consider this code:
function f(model) {
if model.is_rate {
return model.value * model.rate;
} else {
return model.value;
}
}
Extracting each branch into its own function:
function f(model) {
if model.is_rate {
return compute_factor(model);
} else {
return compute_standard(model);
}
}
question : How do we pick the signatures of compute_factor
and compute_standard
?
The default choice is outside-in naming: maintaining the name model
. This is what automated refactoring tools propose.
Instead let’s refine names within their new context: inside-out naming.
Don’t:
# keeps caller’s generic “model” name
function compute_factor(model) {
return model.value * model.rate;
}
function compute_standard(model) {
return model.value;
}
Do:
# recontextualizes names
function compute_factor(factor_model) {
return factor_model.value * factor_model.special;
}
function compute_value(value_model) {
return value_model.value;
}
This consideration is particularly important when dealing with cases of polymorphic models. Indeed, somebody somewhere eventually needs to know the actual type of the data to do something useful with it.