Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is an acid test for "the same level of abstraction" when writing composed functions / methods?

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 ?

like image 728
Gishu Avatar asked Jun 09 '11 10:06

Gishu


2 Answers

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

like image 189
BonyT Avatar answered Oct 15 '22 13:10

BonyT


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...

  • you have a variable in the function that is only used for part of the function.
  • you have multiple loops in the function.
  • you have multiple if statements who's conditions are independent of each other.

I hope others will add to the above...

like image 35
Daniel T. Avatar answered Oct 15 '22 13:10

Daniel T.