Context: I need to explain "composed methods" to a group of mixed-experience.
I think I heard about it first while reading Beck's Smalltalk Best practices. I've personally not had too many issues writing such methods - however in the local code-wilderness, I've seen quite a few instances where the lack of composed methods had created indecipherable Blobs... and I was in the minority. So I'm taking them through CleanCode - where this one popped up again.
The premise is quite simple.
"Functions should be short, do one thing well and have an intention-revealing name. Each step in the body of the method should be at the same level of abstraction."
What I'm struggling with a check for the "same level of abstraction".. viz.. forgive the pun a bit abstract for beginners.
My current explanation would be similar to SICP's "wishful thinking". (Imagine the ideal set of steps and then worry about implementation/making it happen.").
Does anyone have a better set of rules / an acid test to evaluate your decisions while writing composed methods ?
Same level of abstraction - examples:
void DailyChores()
{
Dust();
Hoover();
MopKitchenFloor();
AddDirtyClothesToWashingMachine();
PlaceDetergentInWashingMachine();
CloseWashingMachineDoor();
StartWashingMachine();
Relax();
}
Hopefully it should be clear that the WashingMachine saga would be better extracted into a separate method entited WashDirtyLaundry();
Arguably the MopKitchenFloor should also be in a separate method entitled CleanKitchen() as quite likely you would want to extend this in the future to include WashPots(), DefrostFridge() etc.
So a better way would be to write as follows:
void DailyChores()
{
Dust();
Hoover();
CleanKitchen(CleaningLevel.Daily);
WashDirtyClothes();
Relax();
}
void WashDirtyClothes()
{
AddDirtyClothesToWashingMachine();
PlaceDetergentInWashingMachine();
CloseWashingMachineDoor();
StartWashingMachine();
}
void CleanKitchen(CleaningLevel level)
{
MopKitchenFloor();
WashPots();
if(level == CleaningLevel.Monthly)
{
DefrostFridge();
}
}
enum CleaningLevel
{
Daily,
Weekly,
Monthly
}
In terms of "rules" to apply to code not following this principle:
1) Can you describe what the method does in a single sentence without any conjunctions (e.g. "and")? If not split it until you can. e.g. In the example I have AddDirtyClothesToWashingMachine() and PlaceDetergentInWashingMachine() as separate methods - this is correct - to have the code for these 2 separate tasks inside one method would be wrong - however see rule 2.
2) Can you group calls to similar methods together into a higher level method which can be described in a single sentence. In the example, all of the methods relating to washing clothes are grouped into the single method WashDirtyClothes(). Or in consideration of rule 1, the methods AddDirtyClothesToWashingMachine() and PlaceDetergentInWashingMachine() could be called from a single method AddStuffToWashingMachine():
void AddStuffToWashingMachine()
{
AddDirthClothesToWashingMachine();
PlaceDetergentInWashingMachine();
}
3) Do you have any loops with more than a simple statement inside the loop? Any looping behaviour should be a separate method. Ditto for switch statements, or if, then else statements.
Hope this helps
I take "acid test" to mean you would like some concrete rules that help embody the abstract concept in question. As in "You might have mixed levels of abstraction if..."
You might have mixed levels of abstraction if...
I hope others will add to the above...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With