General Programming PrinciplesΒΆ
This guide covers universal programming principles that apply across all programming languages and development scenarios.
π― Fundamental PrinciplesΒΆ
DRY (Don't Repeat Yourself)ΒΆ
Avoid duplicating code or logic throughout your application.
ProblemΒΆ
# Bad: Repeated logic
def calculate_discount_price(price, discount_percent):
discounted_price = price - (price * discount_percent / 100)
return discounted_price
def calculate_tax_price(price, tax_percent):
taxed_price = price + (price * tax_percent / 100)
return taxed_price
# Similar calculation logic repeated
SolutionΒΆ
# Good: Extract common logic
def calculate_percentage_adjustment(base_price, adjustment_percent):
return base_price + (base_price * adjustment_percent / 100)
def calculate_discount_price(price, discount_percent):
return calculate_percentage_adjustment(price, -discount_percent)
def calculate_tax_price(price, tax_percent):
return calculate_percentage_adjustment(price, tax_percent)
KISS (Keep It Simple, Stupid)ΒΆ
Write simple, readable code that's easy to understand and maintain.
ProblemΒΆ
// Bad: Overly complex
public boolean isValidEmail(String email) {
return email != null &&
email.contains("@") &&
email.indexOf("@") == email.lastIndexOf("@") &&
email.indexOf(".") > email.indexOf("@") &&
email.lastIndexOf(".") < email.length() - 2;
}
SolutionΒΆ
// Good: Simple and clear
public boolean isValidEmail(String email) {
if (email == null) return false;
int atIndex = email.indexOf("@");
int lastDotIndex = email.lastIndexOf(".");
return atIndex > 0 &&
atIndex == email.lastIndexOf("@") &&
lastDotIndex > atIndex &&
lastDotIndex < email.length() - 2;
}
// Better: Use regex or email validation library
public boolean isValidEmail(String email) {
return email != null && email.matches("^[A-Za-z0-9+_.-]+@(.+)$");
}
SOLID PrinciplesΒΆ
Five object-oriented design principles for maintainable software.
S - Single Responsibility PrincipleΒΆ
A class should have only one reason to change.
# Bad: Multiple responsibilities
class User:
def save_to_database(self):
# Database logic
pass
def send_email(self):
# Email logic
pass
def validate_input(self):
# Validation logic
pass
# Good: Single responsibility
class User:
def __init__(self, name, email):
self.name = name
self.email = email
class UserRepository:
def save(self, user):
# Database logic only
pass
class EmailService:
def send_welcome_email(self, user):
# Email logic only
pass
class UserValidator:
def validate(self, user):
# Validation logic only
pass
O - Open/Closed PrincipleΒΆ
Software entities should be open for extension, closed for modification.
# Bad: Need to modify for new shapes
class AreaCalculator:
def calculate_area(self, shape):
if shape.type == "circle":
return 3.14 * shape.radius ** 2
elif shape.type == "rectangle":
return shape.width * shape.height
# Need to modify for new shapes!
# Good: Open for extension
class Shape:
def area(self):
raise NotImplementedError
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14 * self.radius ** 2
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
class AreaCalculator:
def calculate_area(self, shape):
return shape.area() # Works for any shape
YAGNI (You Aren't Gonna Need It)ΒΆ
Don't add functionality until you actually need it.
ProblemΒΆ
// Bad: Adding features "just in case"
public class UserService {
public void createUser(User user) { /* ... */ }
public void updateUser(User user) { /* ... */ }
public void deleteUser(User user) { /* ... */ }
public void exportToCSV(User user) { /* ... */ } // Not needed yet
public void exportToXML(User user) { /* ... */ } // Not needed yet
public void exportToJSON(User user) { /* ... */ } // Not needed yet
}
SolutionΒΆ
// Good: Only implement what's needed now
public class UserService {
public void createUser(User user) { /* ... */ }
public void updateUser(User user) { /* ... */ }
public void deleteUser(User user) { /* ... */ }
// Add export features when actually needed
}
π§ Code Quality PrinciplesΒΆ
ReadabilityΒΆ
Code should be written for humans to read, not just for computers to execute.
GuidelinesΒΆ
- Meaningful Names: Use descriptive variable and function names
- Consistent Style: Follow language conventions consistently
- Proper Comments: Explain why, not what
- Logical Organization: Group related code together
ExampleΒΆ
# Bad: Unclear code
def p(x, y):
r = []
for i in range(len(x)):
if x[i] > y:
r.append(x[i])
return r
# Good: Clear and readable
def filter_greater_than_threshold(numbers, threshold):
"""Return numbers greater than the given threshold."""
filtered_numbers = []
for number in numbers:
if number > threshold:
filtered_numbers.append(number)
return filtered_numbers
# Better: Use built-in functions
def filter_greater_than_threshold(numbers, threshold):
"""Return numbers greater than the given threshold."""
return [num for num in numbers if num > threshold]
MaintainabilityΒΆ
Code should be easy to modify and extend.
GuidelinesΒΆ
- Small Functions: Each function does one thing well
- Loose Coupling: Minimize dependencies between components
- High Cohesion: Group related functionality together
- Configuration: Externalize configuration values
ExampleΒΆ
# Bad: Hard to maintain
def process_data():
# Database connection hardcoded
conn = sqlite3.connect("/path/to/database.db")
# Business logic mixed with data access
data = conn.execute("SELECT * FROM users WHERE age > 18").fetchall()
# Processing logic mixed with output
for row in data:
if row[3] > 1000: # Magic number
print(f"High value user: {row[1]}")
else:
print(f"Regular user: {row[1]}")
# Good: Easy to maintain
def process_data():
config = load_config()
db_connection = create_database_connection(config.database_url)
adult_users = get_adult_users(db_connection)
process_user_list(adult_users, config.high_value_threshold)
def get_adult_users(connection):
return connection.execute(
"SELECT * FROM users WHERE age > ?",
(18,)
).fetchall()
def process_user_list(users, high_value_threshold):
for user in users:
if user.balance > high_value_threshold:
print(f"High value user: {user.name}")
else:
print(f"Regular user: {user.name}")
TestabilityΒΆ
Code should be easy to test.
GuidelinesΒΆ
- Pure Functions: Avoid side effects when possible
- Dependency Injection: Pass dependencies as parameters
- Single Responsibility: Easy to test small, focused functions
- Mock Dependencies: Use test doubles for external dependencies
ExampleΒΆ
# Bad: Hard to test (depends on external API)
def get_user_data(user_id):
response = requests.get(f"https://api.example.com/users/{user_id}")
return response.json()
# Good: Easy to test (dependency injection)
def get_user_data(user_id, http_client):
response = http_client.get(f"https://api.example.com/users/{user_id}")
return response.json()
# Test
class MockHttpClient:
def get(self, url):
return MockResponse({"id": 123, "name": "Test User"})
def test_get_user_data():
mock_client = MockHttpClient()
user_data = get_user_data(123, mock_client)
assert user_data["name"] == "Test User"
π― Design PatternsΒΆ
Strategy PatternΒΆ
Encapsulate algorithms and make them interchangeable.
# Strategy interface
class SortingStrategy:
def sort(self, data):
raise NotImplementedError
# Concrete strategies
class BubbleSort(SortingStrategy):
def sort(self, data):
# Bubble sort implementation
return sorted_data
class QuickSort(SortingStrategy):
def sort(self, data):
# Quick sort implementation
return sorted_data
# Context
class Sorter:
def __init__(self, strategy):
self.strategy = strategy
def sort_data(self, data):
return self.strategy.sort(data)
# Usage
sorter = Sorter(QuickSort())
result = sorter.sort_data([3, 1, 4, 1, 5])
Factory PatternΒΆ
Create objects without specifying exact classes.
# Product interface
class DatabaseConnection:
def connect(self):
raise NotImplementedError
# Concrete products
class MySQLConnection(DatabaseConnection):
def connect(self):
return "Connected to MySQL"
class PostgreSQLConnection(DatabaseConnection):
def connect(self):
return "Connected to PostgreSQL"
# Factory
class DatabaseConnectionFactory:
@staticmethod
def create_connection(db_type):
if db_type == "mysql":
return MySQLConnection()
elif db_type == "postgresql":
return PostgreSQLConnection()
else:
raise ValueError(f"Unknown database type: {db_type}")
# Usage
connection = DatabaseConnectionFactory.create_connection("mysql")
connection.connect()
π Related ResourcesΒΆ
- Clean Code - Robert C. Martin
- The Pragmatic Programmer - Andrew Hunt & David Thomas
- Design Patterns - Gang of Four
- Refactoring - Martin Fowler
π Related GuidesΒΆ
- Code Organization - Structuring your codebase
- Debugging Strategies - Troubleshooting techniques
- Documentation Standards - Writing good documentation
π Language-Specific Best PracticesΒΆ
- Java Best Practices - Java-specific guidelines
- Python Best Practices - Python-specific guidelines
- C Best Practices - C-specific guidelines
- Oracle Best Practices - Oracle-specific guidelines