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.
consider the variable
const p = [] //list of pets
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 = []
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"
}
]
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 = () => {}
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)
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.
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`)
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`)
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}`)
)
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 )
}
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);
Recap
There are 3 basic principles we must follow in order to write clean code in a functional programming paradigm.
- Name things meaningfully
- Do not Repeat Yourself
- 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
Top comments (10)
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. 👏👏👏👏Yes you are correct sir
+1 for the code potatoe.
Thank u !
the
getCatsAnd...
method kind we called anensure...
and everyone new that these methods did stuff that was too bullshit to call properly.Thanks for the potatoe
You got the potato from the "Potato Pirate" card game right?
Some comments may only be visible to logged-in visitors. Sign in to view all comments.