= 10 # no of patients
n
= 10 # no of patients no_pat
How to Write Clean Code?
1 How to Write Clean Code?
Writing clean code is about taking certain guiding principles into consideration when writing code.
1.1 Use Descriptive Names
The names of variables, functions and classes need to be intentionally revealing, pronounceable and need to reflect what a function does and what the variables are. If a name requires a comment, then the name does not reveal its intent. In addition it is recommended that you keep naming conventions standard in our code. You can find information on PEP 8 for Python or R style guide
As a general rule keep the names of the variables and classes as nouns and the names of the functions as verbs.
1.1.1 Poor Practice
<- 10 # no of patients
n
<- 10 # no of patients no_pat
1.1.2 Best Practice
Variable Name
= 10 number_of_patients
Function Name
get_number_of_patients()
Class Name
PatientService
Variable Name
<- 10 number_of_patients
Note: number.of.patients
is widely used and even considered best practice among R users. If you move around different languages it would be restrictive and cause syntax conflicts.
Function Name
get_number_of_patients()
Class Name
PatientService
1.2 Avoid Disinformation
You must avoid leaving false clues that obscure the meaning of the code. Do not refer to something like a list if it is not a list. The word has a specific meaning and it may lead to false information.
1.2.1 Poor Practice
= (1, 2, 1, 1, 2, 2, 2)
gender
=["Joe", "Charlie", "Rita", "Alison", "Dave"] student_table
<- c(1, 2, 1, 1, 2, 2, 2)
gender
<- c("Joe", "Charlie", "Rita", "Alison", "Dave") student_table
1.2.2 Best Practice
= ("male", "female", "male", "male", "female", "female", "female")
gender
=["Joe", "Charlie", "Rita", "Alison", "Dave"] student_list
<- c("male", "female", "male", "male", "female", "female", "female")
gender
<- c ("Joe", "Charlie", "Rita", "Alison", "Dave") student_list
1.3 Make Meaningful Distinctions
When writing code, you should not write solely to satisfy the compiler or interpreter. It is not best practice to add number series in variable, class or method names. You need to distinguish names in such a way that the reader knows what the differences are.
1.3.1 Poor Practice
import pandas as pd
= {'patient_id': [1, 2, 3, 4], 'cancer': [1, 1, 2, 3]}
cancer1 = pd.DataFrame(cancer1)
cancer2
cancer2
<- c(1, 1, 2, 3)
cancer<- c(1, 2, 3, 4)
patientId
<-cbind(patientId, cancer)
cancer2 cancer2
1.3.2 Best Practice
import pandas
= [
patient_cancer_list 'patient_id': 1, 'cancer_stage': 1},
{'patient_id': 2, 'cancer_stage': 1},
{'patient_id': 3, 'cancer_stage': 2},
{'patient_id': 4, 'cancer_stage': 4}]
{
= pandas.DataFrame(patient_cancer_list)
patient_cancer_dataframe
patient_cancer_dataframe
library(plyr)
<- list(
patientCancerList list('patientId' = 1, 'cancerStage' = 1),
list('patientId' = 2, 'cancerStage' = 1),
list('patientId' = 3, 'cancerStage' = 2),
list('patientId' = 4, 'cancerStage' = 4))
<- ldply(patientCancerList, data.frame)
patientCancerDataframe patientCancerDataframe
1.5 Don’t Repeat Yourself (DRY)
Don’t repeat yourself promotes that the code you create should be unique, avoiding or reducing duplicated code. Having same code in different places makes maintainability harder, if you make any changes to the code it needs to be updated in different places instead of just one.
Duplicated code also adds complexity and makes the code excessively large. Often when you find yourself creating duplicated code, that’s a good usage for a function.
1.5.1 Poor Practice
= [80,1.65]
person1 = [44, 1.45]
person2
= int(person1[0]/ person1[1]**2)
bmi_person1 print ("bmi of person1 is ", bmi_person1)
= int(person2[0]/ person2[1]**2)
bmi_person2 print ("bmi of person1 is ", bmi_person2)
<- c(80,1.65)
person1 <- c(44, 1.45)
person2
<- (person1[1]/ person1[2]**2)
bmi_person1 cat ("bmi of person1 is ", bmi_person1)
<- (person2[1]/ person2[2]**2)
bmi_person2 cat ("bmi of person1 is ", bmi_person2)
1.5.2 Best Practice
def calculate_bmi(name, weight_kg, height_m):
= int(weight_kg/height_m **2)
bmi return ("bmi of",name ,"is", bmi)
<- function(name, weight_kg, height_m){
calculate_bmi <-(weight_kg/height_m **2)
bmi cat ("bmi of",name ,"is", bmi)
}
1.6 Let One Function Perform Only One Task
Each function should just do one task.
That task should be done well, and in a robust way.
If a function does more than one task, it should be split into multiple functions, where each function does one sub-task.
A function should not do other things in the background, just the single task it’s written for.
“The first rule of functions is that they should be small. The second rule of functions is that they should be smaller than that.” - Robert C Martin, Clean Code: A Handbook of Agile Software Craftsmanship
The idea is to keep the code together that can get damaged for the same reason of change. When changing something, you want to impact as few things as possible.
Avoid keeping code that’s not used - its confusing and usually falls behind in maintenance so it can’t be used (the same goes for carrying code without using it).
1.6.1 Poor Practice
def get_sum_of_even_numbers(numbers):
= [each_number for each_number in numbers if each_number % 2 == 0]
even_numbers = len(even_numbers)
even_number_count = sum(even_numbers)
sum_of_even_numbers return(sum_of_even_numbers)
<- function(numbers){
getSumOfEvenNumbers <- numbers[numbers %% 2 ==0]
evenNumbers <- length(evenNumbers)
evenNumbersCount <- sum(evenNumbers)
sumOfEvenNumbers return(sumOfEvenNumbers)
}
1.6.2 Best Practice
def get_sum_of_even_numbers(numbers):
= get_even_numbers(numbers)
even_numbers = sum(even_numbers)
sum_of_even_numbers return sum_of_even_numbers
def get_even_numbers(numbers):
= [each_number for each_number in numbers if is_even(each_number)]
even_numbers return even_numbers
<-function(numbers){
getSumOfEvenNumbers<- getEvenNumbers(numbers)
evenNumbers <- sum(evenNumbers)
sumOfEvenNumbers return(sumOfEvenNumbers)
}
<-function(numbers){
getEvenNumbers<- numbers[areEven(numbers)]
evenNumbers return(evenNumbers)
}
1.7 Keep It Simple
Nobody likes debugging, maintaining, or making changes to complex code. According to the keep it simple principle, you need to keep our code as simple as possible. If your function has too many arguments, perhaps the function is doing too much and you need to split it.
Remember, the simpler the code, the simpler it is to understand.
1.7.1 Poor Practice
def count_even_numbers(first_number, second_number, third_number, fourth_number, fifth_number):
= (first_number, second_number, third_number, fourth_number, fifth_number)
given_numbers = get_even_numbers(given_numbers)
even_numbers = len(even_numbers)
even_numbers_count return even_numbers_count
def get_even_numbers(numbers):
= [each_number for each_number in numbers if is_even(each_number)]
even_numbers return even_numbers
<- function(firstNumber, secondNumber, thirdNumber, fourthNumber, fifthNumber){
countEvenNumbers <- c(firstNumber, secondNumber, thirdNumber, fourthNumber, fifthNumber)
givenNumbers <- getEvenNumbers(givenNumbers)
evenNumbers <- length(evenNumbers)
evenNumbersCount return (evenNumbersCount)
}
<-function(numbers){
getEvenNumbers<- numbers[areEven(numbers)]
evenNumbers return(evenNumbers)
}
1.7.2 Best Practice
def count_even_numbers(numbers):
= get_even_numbers(numbers)
even_numbers = len(even_numbers)
even_numbers_count return even_numbers_count
def get_even_numbers(numbers):
= [each_number for each_number in numbers if is_even(each_number)]
even_numbers return even_numbers
<- function(numbers){
countEvenNumbers <- getEvenNumbers(numbers)
evenNumbers <- length(evenNumbers)
evenNumbersCount return (evenNumbersCount)
}
<-function(numbers){
getEvenNumbers<- numbers[areEven(numbers)]
evenNumbers return(evenNumbers)
}
1.8 No To Nesting
Nested loops are difficult to read and understand. You should keep conditional statements as flat and easy to understand as possible. It is good practice to create separate functions instead of nested loops.
1.8.1 Poor Practice
= (-1)
first_element = (-2)
second_element = (-3)
third_element
if (first_element < 0):
if (second_element < 0):
if (third_element < 0):
print('all negatives')
or
if (first_element < 0 and second_element < 0 and third_element < 0):
print('all negatives')
<- (-1)
firstElement <- (-2)
secondElement <- (-3)
thirdElement
if (firstElement < 0){
if (secondElement < 0){
if (thirdElement < 0){
print('all negatives')}}}
or
if (firstElement < 0 & secondElement < 0 & thirdElement < 0){
print('all negatives')
}
1.8.2 Best Practice
def all_elements_negative(elements):
= get_positive_elements(elements)
positive_elements = len(positive_elements)
number_of_positive_elements return number_of_positive_elements == 0
def get_positive_elements(elements):
= [each_element for each_element in elements if each_element > 0]
positive_elements return positive_elements
= [first_element, second_element, third_element]
all_elements if (all_elements_negative(all_elements)):
print('all_negatives')
<- function(elements){
allElementsNegative <- getPositiveElements(elements)
positiveElements <- length(positiveElements)
numberOfPositiveElements return (numberOfPositiveElements == 0)
}
<-function(numbers){
getPositiveElements<- numbers[numbers > 0]
positiveElements return(positiveElements)
}
<- c(firstElement, secondElement, thirdElement)
allElements if (allElementsNegative(allElements)){
print('all negatives')
}
1.9 Code Should Read Like a Book
Our code should be structured and organised in a such way that anyone who looks at our code would be able to grasp its purpose without spending hours digging into it, just as a book is structured through chapter and paragraphs.
Code should be written in order it is called.
1.9.1 Poor Practice
def get_even_numbers(numbers):
= [each_number for each_number in numbers if is_even(each_number)]
even_numbers return even_numbers
def get_sum_of_even_numbers(numbers):
= get_even_numbers(numbers)
even_numbers = sum(even_numbers)
sum_of_even_numbers return sum_of_even_numbers
def is_even(number):
return number % 2 == 0
<-function(numbers){
getEvenNumbers<- numbers[areEven(numbers)]
evenNumbers return(evenNumbers)
}
<- function(numbers){
getSumOfEvenNumbers <- getEvenNumbers(numbers)
evenNumbers <- sum(evenNumbers)
sumOfEvenNumbers return(sumOfEvenNumbers)
}
<- function(numbers){
areEven return(numbers %% 2 == 0)
}
1.9.2 Best Practice
def get_sum_of_even_numbers(numbers):
= get_even_numbers(numbers)
even_numbers = sum(even_numbers)
sum_of_even_numbers return sum_of_even_numbers
def get_even_numbers(numbers):
= [each_number for each_number in numbers if is_even(each_number)]
even_numbers return even_numbers
def is_even(number):
return number % 2 == 0
<-function(numbers){
getSumOfEvenNumbers<- getEvenNumbers(numbers)
evenNumbers <- sum(evenNumbers)
sumOfEvenNumbers return(sumOfEvenNumbers)
}
<-function(numbers){
getEvenNumbers<- numbers[areEven(numbers)]
evenNumbers return(evenNumbers)
}
<- function(numbers){
areEven return(numbers %% 2 == 0)
}
1.4 Comments
You write comments with the intention of explaining what code does. The issue with comments is they are not always kept up to date. The code is frequently updated or moved from one place to another, but the old comments remain unchanged. As a result, the comments no longer reflect the code. In addition, code should tell what each code is doing not comments. Instead of writing comments to explain code you need to focus on making the code readable.
1.4.1 Poor Practice
1.4.2 Best Practice