Activities > Design Principles for Coding

Schedule > Design Principles for Coding

What Makes Code “Good”?

Good code is code that’s easy to understand and easy to change. Good code is clear, has good test coverage, is maintainable, and works.

There are principles that help us write good code. These principles are guidelines, not rules. They help us make decisions when coding. Today, we’ll learn four key principles.

Assigned Reading: See Clean Code Best Practices for a comprehensive reference guide.

1. Cohesion

Cohesion is how well the parts of a module/class/function work together.

  • Low cohesion: Parts of the class do unrelated things
  • High cohesion: All parts work toward one goal

1.1. Low cohesion example

# Low cohesion: Does too many things
class UserService:
    def create_user(self, username, email, password):
        # Create user logic
        pass
    
    def send_email(self, to, subject, body):
        # Email logic (unrelated to user creation)
        pass
    
    def calculate_statistics(self):
        # Statistics logic (unrelated to user creation)
        pass

1.2. High cohesion example

# High cohesion: Does one thing well
class UserService:
    def create_user(self, username, email, password):
        # Create user logic
        pass
    
    def update_user(self, user_id, data):
        # Update user logic
        pass
    
    def delete_user(self, user_id):
        # Delete user logic
        pass

Takeaway: High cohesion means each class/function has one clear responsibility.

2. Coupling

Coupling is how much one module depends on another.

  • Low coupling: Modules are independent (Good)
  • High coupling: Modules are tightly connected

2.1. High coupling

# High coupling: Directly depends on database
class UserService:
    def get_user(self, user_id):
        db = get_db()
        return db.query(User).filter(User.id == user_id).first()

2.2. Low coupling

# Low coupling: Depends on abstraction
class UserService:
    def __init__(self, user_repository):
        self.user_repository = user_repository
    
    def get_user(self, user_id):
        return self.user_repository.find_by_id(user_id)

Takeaway: Low coupling means changes in one module don’t break others.

3. DRY (Don’t Repeat Yourself)

DRY stands for “Don’t Repeat Yourself.”

  • Why: Repeated code is hard to maintain
  • When: Extract common code into functions/classes

3.1. Not Dry

# Not DRY: Repeated code
def create_group(name, description):
    # Validation logic
    if not name or len(name) > 100:
        raise ValueError("Invalid name")
    if description and len(description) > 1000:
        raise ValueError("Invalid description")
    # Create logic
    group = Group(name=name, description=description)
    db.add(group)
    db.commit()
    return group

def create_course(title, description):
    # Validation logic (repeated!)
    if not title or len(title) > 200:
        raise ValueError("Invalid title")
    if description and len(description) > 1000:
        raise ValueError("Invalid description")
    # Create logic
    course = Course(title=title, description=description)
    db.add(course)
    db.commit()
    return course

3.2. Dry

Adding a helper function to handle validation consistently:

# DRY: Extract common code
def validate_text_field(value, field_name, max_length):
    if not value or len(value) > max_length:
        raise ValueError(f"Invalid {field_name}")

def create_group(name, description):
    validate_text_field(name, "name", 100)
    validate_text_field(description, "description", 1000)
    group = Group(name=name, description=description)
    db.add(group)
    db.commit()
    return group

def create_course(title, description):
    validate_text_field(title, "title", 200)
    validate_text_field(description, "description", 1000)
    # Create logic
    course = Course(title=title, description=description)
    db.add(course)
    db.commit()
    return course

Takeaway: DRY means extract common code, but don’t over-abstract.

4. Size

Size refers to how long functions/classes are.

  • Small is better: Easier to understand, test, and maintain
  • Rule of thumb: Functions < 20 lines, classes < 200 lines

4.1. Too Long

# Too long: Hard to understand
def process_user_registration(username, email, password, profile_data):
    # 50 lines of validation
    # 30 lines of database operations
    # 20 lines of email sending
    # 15 lines of logging
    # Total: 115 lines!

4.2. Better

# Better: Break into smaller functions
def validate_registration_data(username, email, password):
    # 10 lines
    pass

def create_user_account(username, email, password):
    # 15 lines
    pass

def send_welcome_email(email):
    # 10 lines
    pass

def process_user_registration(username, email, password, profile_data):
    validate_registration_data(username, email, password)
    user = create_user_account(username, email, password)
    send_welcome_email(email)
    return user

Takeaway: Small functions are easier to understand, test, and maintain.

5. Other Considerations

  • Magic Numbers: Hard-coded values with unclear meaning (extract to named constants)
  • Unclear Names: Variables/functions that don’t clearly describe what they do
  • Deep Nesting: Multiple levels of if/for/while statements (use early returns or extract functions)
  • Excessive Comments: Comments explaining what code does (code should be self-explanatory; comments should explain why)
  • Too Many Function Arguments: Functions with many parameters (consider using objects/structs)
  • Global Variables: Using global state instead of passing data as arguments (makes code harder to test)
  • Side Effects: Functions that modify state outside their scope (mutate globals, modify inputs, change database) - prefer pure functions when possible

See Clean Code Best Practices for a comprehensive reference guide.

Summary

  • Cohesion: One responsibility per class/function
  • Coupling: Minimize dependencies
  • DRY: Don’t repeat code
  • Size: Keep functions and classes small

These principles help us write maintainable code.

UNC Asheville Department of Computer Science