How to write Clean and Modular Code 🤩👨‍💻
Tags: beginners, codenewbie, codequality, productivity
Published: 2021-09-06 12:57:46

> “Any fool can write code that a computer can understand. Good programmers write code that humans can understand.” – Martin Fowler

I had not said these lines, so no **offense**. 😶 

## Terminologies	

- **Clean code** : Code that is readable, simple, and concise. Clean production-quality code is crucial for collaboration and maintainability in software development.
- **Modular code** : Code that is logically broken up into functions and modules. Modular production-quality code that makes our code more organized, efficient, and reusable.
- **Module** : A file. Modules allow code to be reused by encapsulating them into files that can be imported into other files.
![Modular Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1i9yfofdjt6glw87e6s5.jpg) <hr />

## Writing clean code

### Use Meaningful Names.
• **Be descriptive and imply type** : For booleans, we can prefix with `is_` or `has_` to make it clear it is a condition. We can also use parts of speech to imply types, like using verbs for functions and nouns for variables.
• **Be consistent but clearly differentiate** : `age_list` and `age` is easier to differentiate than `ages` and `age`.
• **Avoid abbreviations and single letters** : We can determine when to make these exceptions based on the audience of our code and if it is counters and common math variables.
• **Long names aren't the same as descriptive names** : We should be descriptive, but only with relevant information. For example, good function names describe what they do well without including details about implementation or highly specific uses.

### Use Whitespace Properly.
• **Organize your code with consistent indentation** : the standard is to use four spaces for each indent. We can make this a default in our text editor.
• Separate sections with blank lines to keep our code well organized and readable.
• If you are coding in **python**, try to limit your lines to around 79 characters, which is the guideline given in the PEP 8 style guide. In many good text editors, there is a setting to display a subtle line that indicates where the 79 character limit is.

### For Example :
Imagine we are writing a program that executes a number of tasks and categorizes each task based on its execution time. Below is a small snippet of this program.
```
t = end_time - start  # compute execution time
c = category(t)  # get category of task
print('Task Duration: {} seconds, Category: {}'.format(t, c)
```

**How we can make this code look cleaner?**

The following naming changes could make this code cleaner.
- Rename the variable `start` to `start_time` to make it consistent with `end_time`.
- Rename the variable `t` to `execution_time` to make it more descriptive.
- Rename the function `category` to `categorize_task` to match the part of speech.
- Rename the variable `c` to `category` to make it more descriptive.

After the changes the code will look like this :
```
execution_time = end_time - start_time
category = categorize_task(execution_time)
print('Task Duration: {} seconds, Category: {}'.format(execution_time, category)
```
<hr />

## Writing Modular Code

Follow the tips below to write modular code.

- **Tip : DRY (Don't Repeat Yourself)**
Don't repeat yourself! Modularization allows us to reuse parts of our code. Generalize and consolidate repeated code in functions or loops. <br /><br />

- **Tip : Abstract out logic to improve readability**
Abstracting out code into a function not only makes it less repetitive, but also improves readability with descriptive function names. Although our code can become more readable when we abstract out logic into functions, it is possible to over-engineer this and have way too many modules, so we can use our own judgement. <br /><br />


- **Tip : Minimize the number of entities (functions, classes, modules, etc.)**
There are trade-offs to having function calls instead of inline logic. If we have broken up your code into an unnecessary amount of functions and modules, we will have to jump around everywhere if we want to view the implementation details for something that may be too small to be worth it. Creating more modules doesn't necessarily result in effective modularization. <br /><br />

- **Tip : Functions should do one thing**
Each function we write should be focused on doing one thing. If a function is doing multiple things, it becomes more difficult to generalize and reuse. Generally, if there's an "and" in your function name, consider refactoring. <br /><br />

- **Tip : Arbitrary variable names can be more effective in certain functions**
Arbitrary variable names in general functions can actually make the code more readable. <br /><br />

- **Tip : Try to use fewer than three arguments per function**
Try to use no more than three arguments when possible. This is not a hard rule and there are times when it is more appropriate to use many parameters. But in many cases, it's more effective to use fewer arguments. Remember we are modularizing to simplify our code and make it more efficient. If our function has a lot of parameters, we may want to rethink how we are splitting this up.

### For Example :
We have a list of **Test Scores** that we curve in three different ways. Assume that we are an educator who gave out a test that was too difficult or gave a question that was a little unfair (like our college examiners do sometimes). So we decide to figure out a way to boost out student’s scores. 
```
s = [88, 92, 79, 93, 85]
print(sum(s)/len(s))

s1 = []
for x in s:
    s1.append(x + 5)

print(sum(s1)/len(s1))

s2 = []
for x in s:
    s2.append(x + 10)

print(sum(s2)/len(s2))

s3 = []
for x in s:
    s3.append(x ** 0.5 * 10)

print(sum(s3)/len(s3))

# difficult to understand and pretty repetitive
```
For the first two methods, we add a flat curve of 5 points to each scores and 10 points to each score respectively. In third method we applied a square root curve, where we find the square root of each score and multiply it by 10.

Right now, its **difficult to understand** what this code is for and looks pretty **repetitive**.

Now by following the tips we can modify the code as
```
import math
import numpy as np

def flat_curve(arr, n):
    return [i + n for i in arr]

def square_root_curve(arr):
    return [math.sqrt(i) * 10 for i in arr]

test_scores = [88, 92, 79, 93, 85]
curved_5 = flat_curve(test_scores, 5)
curved_10 = flat_curve(test_scores, 10)
curved_sqrt = square_root_curve(test_scores)

for score_list in test_scores, curved_5, curved_10, curved_sqrt:
    print(np.mean(score_list))

# clean and modular
```
This is an example of **clean** and **modular code**.
![gif](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/elds6rv3g3q3ff4j40kj.gif) <hr />

## Conclusion 
Follow these tips to write clean and modular code:
- Use Meaningful Names
- Use Whitespace Properly
- DRY (Don't Repeat Yourself)
- Abstract out logic to improve readability
- Minimize the number of entities (functions, classes, modules, etc.)
- Functions should do one thing
- Arbitrary variable names can be more effective in certain functions
- Try to use fewer than three arguments per function
	
## Thanks for reading!
Feel free to give any suggestions. :-)

## Reference
AWS Machine Learning Foundation Course on Udacity

## You can connect with me on
- [Twitter](https://twitter.com/Prxtikk)
- [LinkedIn](https://www.linkedin.com/in/prxtikk/)