In a program divided up into many functions by which it is intended that they execute themselves one after another, when (if ever) is it preferred to:
A) Execute the functions one after another in main()
?
or
B) Execute one function in main()
, and have that function daisy chain to the rest of the functions that need to be executed?
To illustrate this
Program FlowChart:
Start -> Make foo -> Do bar? -> True -> Say Goodbye -> End
A:
void makeFoo() {
[...]
return;
}
bool doBar() {
bool bar;
[...]
return bar;
}
void sayGoodbye() {
[...]
return;
}
int main {
makeFoo();
if (doBar()) {
sayGoodbye();
}
return 0;
}
B: (Daisy Chain)
void makeFoo() {
[...]
doBar();
return;
}
void doBar() {
bool bar;
[...]
if (bar) {
sayGoodbye();
}
return;
}
void sayGoodbye() {
[...]
return;
}
int main {
makeFoo();
return 0;
}
Best Answer
Daisy chain when it is clear to the next developer why you did it that way.
There is no one answer to this, but I can give you a good rule of thumb: If the name of the function implies that its job is to do one function and call another, then it is safe to chain them.
There are times where two functionalities do really need to chain. Consider the classic example of error handling
If this pattern shows up all the time, the next developer is going to get sore reading it over and over. Worse, they may get lazy or forget, causing unexpected results. However,
haltAndCatchFire
on its own is a pretty useful function to have, so we don't want to bury that functionality intodoSomething
, just to never see it again. As a solution:Its long, but now it is very clear that you intend to daisy chain. A developer who does not want to follow you into
doSomething
can generally assume that you'll callhaltAndCatchFire
if anything goes wrong, so you have successfully transmitted information to the next developer. They can keep readingmain()
without having to dodge and weave through multiple functions.Your naming choice is up to you, as long as it is clear. As an example, on one suite of software I developed, there was a pattern:
It was understood (social contract) that
getValue()
should call exception handling functions if something goes wrong. TryGetValue should just return (often returning a dummy value that let us know something went wrong). For other situations, where the social contract was not so clear, we had functions likegetRegressionResultsForData()
, which did some functions to get the data, then calledgetRegressionResults()
on it.In summary, you should never chain in a situation where a future developer could be mislead by skimming over a function (instead of diving into all sub-functions to look for chains).