3 clean code principles for the functional programming beginner
Ayabonga Qwabi

Ayabonga Qwabi @ayabongaqwabi

About: I’m a South African Software Developer who thrives on transforming complex ideas into intuitive, user-friendly applications. My work is a mix of technical precision and creative problem-solving.

Location:
Komani, South Africa
Joined:
Jul 23, 2018

3 clean code principles for the functional programming beginner

Publish Date: Oct 13 '19
157 10

1. Name things meaningfully

When you name a variable the name you give it must tell us that variable's whole life story. It must tell us who the variable is and why it is. The name is a selling point of a variable and that's why it must be properly described.

It should tell you why it exists, what it does, and how it is used. If a name requires a comment, then the name is not meaningful.

Alt Text

consider the variable

const p = [] //list of pets
Enter fullscreen mode Exit fullscreen mode

P can be anything, which would make it harder to read when this variable is used within a complex loop or function.

This is a more meaningful name

const bertsPetList = []
Enter fullscreen mode Exit fullscreen mode

because it tells you

What? list of pets belonging to bert
Why? for code operations that are interested in Bert and his pets
How? as a standard js array

1.2 Function names must reveal intent

When naming a function we must also think of "What?", "Why?" and "How?"

What does it do?
Why does it do this?
How does it do this?

Take for example you wanted to get a list of animals specific owners might have that are allowed to stay with their owner inside the house.

const bertsPets = [
    {
       name: "Snizzles"
       type: "nope"
       lives: "outdoors"
    },
    {
       name: "Terrance"
       type: "danger-woof"
       lives: "outdoors"
    },
    {
       name: "Kevin"
       type: "doggo"
       lives: "indoors"
    }
]
Enter fullscreen mode Exit fullscreen mode

For instance the name for such a function could be findPets, as much as the name makes sense it wouldn't be descriptive enough for the next programmer who's going to read your code to easily understand what's going on.

So maybe you would try the name findPetsThatLiveIndoors

Which is good but in terms of DRY (we'll get into this in the next section) you are doing your code a disservice, because for every living area type you will have to create a function corresponding to that type
i.e

const findPetsThatLiveIndoors = () => {}
const findPetsThatLiveOutdoors = () => {}
const findPetsThatLiveInOtherPlace1= () => {}
const findPetsThatLiveInOtherPlace2 = () => {}
Enter fullscreen mode Exit fullscreen mode

Thereby unnecessarily repeating yourself. (Which is bad)
So what name can we give our function?

const filterPetsByLivingAreaInList  = () => {}

// which could then be

const filterPetsByLivingAreaInList  = (area, list) => list.filter(pet => pet.lives === area)

// and can produce

const bertsIndoorPets = filterPetsByLivingAreaInList('indoors',bertsPets)

Enter fullscreen mode Exit fullscreen mode

Now this name tells us the
what? pets that live in a specific area
how? by filtering a list
why? to get a list of animals which a specific owner might have that he/she allows to live inside the house

2. Do not Repeat Yourself

The DRY principle simply means you should not have code duplications.

Alt Text

2.1 Variable scopes

Don't recreate variables for each and every function scope when a global scope can be used
e.g

const getDoggosThatLiveIndoors = () => {
    const doggos = getPetsByType('doggo', bertsPets);
    const doggosThatLiveIndoors = filterPetsByLivingAreaInList('indoors', doggos);
    return doggosThatLiveIndoors;
}

const getDoggosThatLiveOutdoors= () => {
    const doggos = getPetsByType('doggo', bertsPets);
    const doggosThatLiveIndoors = filterPetsByLivingAreaInList('indoors', doggos);
    return doggosThatLiveOutdoors;
}

console.log(`${getDoggosThatLiveIndoors().length} doggos live indoors`)
console.log(`${getDoggosThatLiveOutdoors().length} doggos live outdoors`)
Enter fullscreen mode Exit fullscreen mode

In the above example the variable doggos can be defined in the global scope to avoid re-defining it for every function

const doggos = getPetsByType('doggo', bertsPets);

const getDoggosThatLiveIndoors = () => {
    const doggosThatLiveIndoors = filterPetsByLivingAreaInList('indoors', doggos);
    return doggosThatLiveIndoors;
}

const getDoggosThatLiveOutdoors = () => {
    const doggosThatLiveIndoors = filterPetsByLivingAreaInList('outdoors', doggos);
    return doggosThatLiveOutdoors;
}

console.log(`${getDoggosThatLiveIndoors().length} doggos live indoors`)
console.log(`${getDoggosThatLiveOutdoors().length} doggos live outdoors`)
Enter fullscreen mode Exit fullscreen mode

2.2 Function operations

In the above example the two functions getDoggosThatLiveIndoors and getDoggosThatLiveOutdoors perform the same operation and can therefore be optimized into one

const doggos = getPetsByType('doggo', bertsPets);

const getDoggosByLivingArea = (areaType) => {
    const doggosInArea = filterPetsByLivingAreaInList(areaType, doggos);
    return doggosInArea;
}

const areaTypes = ['indoors', 'outdoors'];

areaTypes.map( type => 
    console.log(`${getDoggosByLivingArea(type).length} doggos live ${type}`)
)
Enter fullscreen mode Exit fullscreen mode

Duplication may be the root of all evil in software. Many principles and practices have been created for the purpose of controlling or eliminating it.

3. Functions should do one thing

When creating our functions we should make sure that they achieve only one defined goal

Now imagine the following function

const favoritePets = ['cat', 'doggo']

const getFavoritePets = (favoritePets, petList) => {
       const ownerHasCats = hasPetType('cats', petList);
       if(!ownerHasCats){
          const cats = [cat1, cat2, cat3]
          const petsWithCats = insertPets(cats, petList)
          return filterPets(favoritePets, petsWithCats )
       }
       return filterPets(favoritePets, petList )
}
Enter fullscreen mode Exit fullscreen mode

This function should only be getting the owner's favorite pets but it also tries to find out if the owner's cats have been added to his pet list and inserts them if they aren't available. This violates the Single Responsibility Principle because this function is doing too many things. It has many responsibilities. It's name is getFavoritePets
not getFavoritePetsAndCheckIfOwnerHasCatsIfNotAddCatsToTheOwnersPetList
😂

A better way of doing this would be

const cats = [cat1, cat2, cat3]

const bertsPetsWithCats = insertPets(cats, bertsPets)

const favoritePets = ['cat', 'doggo']

const getFavoritePets = (favoritePetTypes, petList) => filterPets(favoritePetTypes, petList);

const bertsFavoritePets = getFavoritePets(favoritePets, bertsPetsWithCats);
Enter fullscreen mode Exit fullscreen mode

Recap

There are 3 basic principles we must follow in order to write clean code in a functional programming paradigm.

  1. Name things meaningfully
  2. Do not Repeat Yourself
  3. Functions should do one thing

For more in depth knowledge on clean code I suggest your read the clean code handbook

And We're done :)

Here's a code potato

Alt Text

Comments 10 total

  • Sean Allin Newell
    Sean Allin NewellOct 13, 2019

    +1 for the code potatoe.

  • Matt McMahon
    Matt McMahonOct 13, 2019

    Only thing better than a well named variable is a variable that doesn't need a name at all. Many of these functions could be written in a point-free style and composed or piped together. Add some higher order functions to simplify, e.g. filterPetsBy, and you'd have an excellent follow up to a great beginner article. 👏👏👏👏

  • metz2000
    metz2000Oct 13, 2019

    Using global variables is a smell and common source of bugs, especially in a language like javascript. I'd recommend to read the book Clean Code. It has code examples in Java but the principles are language agnostic.

    • Morgen Peschke
      Morgen PeschkeOct 14, 2019

      I see what he's getting at.

      I don't like how he explained it.

      The idea that the doggos variable shouldn't be duplicated is pretty self-evident, as it's both constant and effectively an additional helper function.

      I doubt it belongs in the global scope, but it's reasonable to put it into the same scope as the functions that use it.

      • Ayabonga Qwabi
        Ayabonga QwabiOct 14, 2019

        You are right it is a constant, I just wanted to highlight the duplication part from a beginners perspective

  • Douglasvincent
    DouglasvincentOct 14, 2019

    Thanks for the potatoe

  • davidvalencia-it
    davidvalencia-itOct 14, 2019

    Thank u !

  • ken11zer01
    ken11zer01Oct 14, 2019

    You got the potato from the "Potato Pirate" card game right?

  • Maroš Beťko
    Maroš BeťkoOct 15, 2019

    the getCatsAnd... method kind we called an ensure... and everyone new that these methods did stuff that was too bullshit to call properly.

Add comment