Table of Contents
Writing Clean, Maintainable Code
Good code isn't just code that works - it's code that's easy to read, understand, and maintain. Learning best practices early will make you a better programmer and save you time in the long run.
Why Code Organization Matters
- Readability: Others (and future you) can understand your code
- Maintainability: Easy to fix bugs and add features
- Collaboration: Teams can work together effectively
- Debugging: Problems are easier to find and fix
- Reusability: Code can be used in multiple projects
Naming Conventions
Variables and Functions
Use clear, descriptive names that explain what the variable or function does.
Good vs Bad Naming
// Bad naming
var x = 25;
var y = "John";
function calc(a, b) { return a * b; }
// Good naming
var userAge = 25;
var userName = "John";
function calculateArea(length, width) {
return length * width;
}
Naming Conventions by Type
- Variables:
userName
,totalScore
,isLoggedIn
- Functions:
calculateTax()
,validateEmail()
,getUserData()
- Constants:
MAX_USERS
,API_URL
,DEFAULT_TIMEOUT
- Classes:
UserAccount
,ShoppingCart
,DatabaseConnection
Code Formatting and Style
Consistent Indentation
Use consistent spacing to show code structure.
Proper Indentation
// Good indentation
function processOrder(order) {
if (order.isValid) {
for (let item of order.items) {
if (item.quantity > 0) {
calculateItemTotal(item);
}
}
return calculateOrderTotal(order);
}
return 0;
}
// Bad indentation
function processOrder(order) {
if (order.isValid) {
for (let item of order.items) {
if (item.quantity > 0) {
calculateItemTotal(item);
}
}
return calculateOrderTotal(order);
}
return 0;
}
Spacing and Line Breaks
- Add spaces around operators:
a + b
nota+b
- Use blank lines to separate logical sections
- Keep lines reasonably short (usually under 80-100 characters)
Comments and Documentation
When to Comment
- Explain WHY, not WHAT: The code shows what, comments explain why
- Complex logic: Help others understand tricky algorithms
- Business rules: Explain domain-specific requirements
- Warnings: Alert about potential issues or limitations
Good Comments
// Calculate tax based on customer location and product type
// Different states have different tax rates for digital vs physical goods
function calculateTax(price, customerState, isDigital) {
// Digital products are tax-exempt in some states
if (isDigital && TAX_EXEMPT_STATES.includes(customerState)) {
return 0;
}
// Apply standard state tax rate
const taxRate = STATE_TAX_RATES[customerState] || DEFAULT_TAX_RATE;
return price * taxRate;
}
// Bad comments (too obvious)
var age = 25; // Set age to 25
age++; // Increment age by 1
Function Documentation
Document what functions do, their parameters, and return values.
Function Documentation
/**
* Validates an email address format
* @param {string} email - The email address to validate
* @returns {boolean} True if email format is valid, false otherwise
* @example
* validateEmail("user@example.com") // returns true
* validateEmail("invalid-email") // returns false
*/
function validateEmail(email) {
const emailRegex = /^[^s@]+@[^s@]+.[^s@]+$/;
return emailRegex.test(email);
}
Function Design Principles
Single Responsibility Principle
Each function should do one thing well.
Single Responsibility Example
// Bad: Function does too many things
function processUser(userData) {
// Validate data
if (!userData.email || !userData.name) return false;
// Save to database
database.save(userData);
// Send welcome email
emailService.sendWelcome(userData.email);
// Log activity
logger.log("User created: " + userData.name);
return true;
}
// Good: Separate functions for each responsibility
function validateUserData(userData) {
return userData.email && userData.name;
}
function saveUser(userData) {
return database.save(userData);
}
function sendWelcomeEmail(email) {
return emailService.sendWelcome(email);
}
function logUserCreation(userName) {
logger.log("User created: " + userName);
}
function processUser(userData) {
if (!validateUserData(userData)) return false;
saveUser(userData);
sendWelcomeEmail(userData.email);
logUserCreation(userData.name);
return true;
}
Keep Functions Small
Aim for functions that fit on one screen (usually 20-30 lines max).
Avoid Deep Nesting
Too many nested if statements make code hard to read.
Reducing Nesting
// Bad: Deep nesting
function processPayment(payment) {
if (payment) {
if (payment.amount > 0) {
if (payment.method === "credit") {
if (payment.cardNumber) {
if (validateCard(payment.cardNumber)) {
return chargeCard(payment);
}
}
}
}
}
return false;
}
// Good: Early returns reduce nesting
function processPayment(payment) {
if (!payment) return false;
if (payment.amount <= 0) return false;
if (payment.method !== "credit") return false;
if (!payment.cardNumber) return false;
if (!validateCard(payment.cardNumber)) return false;
return chargeCard(payment);
}
Error Handling
Handle Errors Gracefully
Don't let your program crash - handle errors appropriately.
Error Handling Example
function divideNumbers(a, b) {
// Check for invalid inputs
if (typeof a !== "number" || typeof b !== "number") {
throw new Error("Both parameters must be numbers");
}
// Check for division by zero
if (b === 0) {
throw new Error("Cannot divide by zero");
}
return a / b;
}
// Usage with error handling
try {
const result = divideNumbers(10, 2);
console.log("Result:", result);
} catch (error) {
console.error("Error:", error.message);
// Handle the error appropriately
}
Code Organization Patterns
Group Related Functions
Organize functions by what they do.
Organized Code Structure
// User-related functions
function createUser(userData) { /* ... */ }
function updateUser(userId, newData) { /* ... */ }
function deleteUser(userId) { /* ... */ }
function getUserById(userId) { /* ... */ }
// Order-related functions
function createOrder(orderData) { /* ... */ }
function calculateOrderTotal(order) { /* ... */ }
function processOrder(orderId) { /* ... */ }
// Utility functions
function formatDate(date) { /* ... */ }
function validateEmail(email) { /* ... */ }
function generateId() { /* ... */ }
Use Constants for Magic Numbers
Replace hard-coded numbers with named constants.
Constants vs Magic Numbers
// Bad: Magic numbers
if (user.age >= 18 && user.age <= 65) {
// Apply standard rate
}
if (order.total > 100) {
// Free shipping
}
// Good: Named constants
const MIN_ADULT_AGE = 18;
const RETIREMENT_AGE = 65;
const FREE_SHIPPING_THRESHOLD = 100;
if (user.age >= MIN_ADULT_AGE && user.age <= RETIREMENT_AGE) {
// Apply standard rate
}
if (order.total > FREE_SHIPPING_THRESHOLD) {
// Free shipping
}
🎯 Code Review Exercise
Improve this code by applying best practices:
function calc(x,y,z){
var r;
if(z=="add"){
r=x+y;
}else if(z=="sub"){
r=x-y;
}else if(z=="mul"){
r=x*y;
}else if(z=="div"){
if(y!=0){
r=x/y;
}else{
r="error";
}
}
return r;
}
Consider: naming, formatting, error handling, and documentation.
Version Control Best Practices
Commit Messages
Write clear commit messages that explain what changed and why.
Good Commit Messages
// Good commit messages
"Add email validation to user registration"
"Fix calculation error in tax function"
"Update user interface for mobile devices"
"Remove deprecated payment processing code"
// Bad commit messages
"fix bug"
"update stuff"
"changes"
"asdf"
Performance Considerations
- Don't optimize prematurely: Write clear code first, optimize later if needed
- Avoid unnecessary loops: Don't repeat work that's already been done
- Use appropriate data structures: Choose the right tool for the job
- Cache expensive operations: Store results of slow calculations
Code Review Checklist
Before considering code "done," check:
- ✅ Variable and function names are clear and descriptive
- ✅ Code is properly formatted and indented
- ✅ Functions are small and focused
- ✅ Complex logic is commented
- ✅ Errors are handled appropriately
- ✅ Code has been tested with different inputs
- ✅ No duplicate code (DRY principle)
- ✅ Constants are used instead of magic numbers