Modular Code Best Practices | Generated by AI

Home 2026.03

Question: How do you write modular code? The rules include using more functions, separating constants/variables, better categorization, and keeping related things together.

Answer:

What Is Modular Code?

Modular programming is not just about writing clean code, self-contained classes, or smaller functions — it’s about seeing your software as a collection of interchangeable modules, each with a well-defined purpose. Instead of one massive application, you break it into smaller, more manageable pieces.


Core Principles

1. Single Responsibility — One Function, One Job

Each function you 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.

Bad example:

def process_and_save_and_notify(data):
    # does 3 things — hard to reuse
    cleaned = data.strip()
    db.save(cleaned)
    email.send("Done!")

Good example:

def clean_data(data):
    return data.strip()

def save_to_db(data):
    db.save(data)

def send_notification(message):
    email.send(message)

2. DRY — Don’t Repeat Yourself

Modularization allows us to reuse parts of our code. Generalize and consolidate repeated code into functions or loops. Abstracting out code into a function not only makes it less repetitive, but also improves readability with descriptive function names.


3. Separate Constants and Configuration

Keep all magic numbers, strings, and configs in one dedicated place so changes are made in one spot only.

# config.py or constants.py
MAX_RETRY = 3
API_URL = "https://api.example.com"
TIMEOUT = 30

# main.py
from config import MAX_RETRY, API_URL

Keep different aspects of the code (data handling, preprocessing, model training, etc.) in separate modules. Encapsulation hides implementation details and exposes only necessary functionalities.

A well-structured project looks like:

project/
├── config/
│   └── settings.py         # constants & config
├── data/
│   ├── loader.py           # loading data
│   └── preprocessor.py     # cleaning data
├── services/
│   └── api_client.py       # API calls
├── utils/
│   └── helpers.py          # shared utilities
└── main.py                 # entry point

5. Layered Architecture

A layered architecture is a common approach where code is organized into distinct layers based on functionality: a Presentation layer (UI logic), a Business logic layer (core rules and processes), and a Data access layer (database interaction). This layered approach fosters modularity, enabling more straightforward modification and maintenance of individual layers without disrupting the entire system.


6. Naming Conventions

Naming conventions can help you avoid confusion, ambiguity, and errors, as well as improve readability and maintainability. You should use a consistent naming convention throughout your code and follow the standards of your programming language. For example, in Python, follow the PEP 8 style guide, which defines rules for naming modules, variables, functions, classes, and constants.

Quick reference:

Element Convention (Python) Example
Variable snake_case user_name
Function snake_case verb get_user()
Constant UPPER_CASE MAX_SIZE
Class PascalCase UserService
Boolean is_ / has_ prefix is_valid

7. Limit Function Arguments

Try to use no more than three arguments per function when possible. This is not a hard rule, but in many cases it’s more effective to use fewer arguments. If a function has a lot of parameters, you may want to rethink how you are splitting it up.


8. Loose Coupling Between Modules

Modules should operate as independent units, connected only through well-defined interfaces. This means you can modify one module’s internal workings without needing to change any others, as long as the interface remains the same.


9. Avoid Over-Modularizing

Programmers can fall into the trap of being overly modular. What starts as a good thing devolves into dividing and subdividing beyond the point of reason with no real-world use case in mind. The adage “premature optimization is the root of all evil” is still relevant — give your software a little time to take shape before refactoring for modularity.


Quick Checklist


References:


Back Donate