DEV Community

Cover image for How to write Clean and Modular Code 🤩👨‍💻
Pratik Raghuvanshi
Pratik Raghuvanshi

Posted on • Edited on

How to write Clean and Modular Code 🤩👨‍💻

“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

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)


Enter fullscreen mode Exit fullscreen mode

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)


Enter fullscreen mode Exit fullscreen mode

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.

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

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

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

  • Tip : Arbitrary variable names can be more effective in certain functions
    Arbitrary variable names in general functions can actually make the code more readable.

  • 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


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

This is an example of clean and modular code.
gif


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

Top comments (0)