No matter which kind of application you're building - you will most likely also use control structures in your code: if statements, for loops, maybe also while loops or switch-case statements.

Control structures are extremely important to coordinate code flow and of course you should use them.

But control structures can also lead to bad or suboptimal code and hence play an important role when it comes to writing clean code.

There are three main areas of improvement, you should be aware of:

  1. Prefer positive checks
  2. Avoid deep nesting
  3. Embrace errors

Side-note: "Avoid deep nesting" is heavily related to clean code practices you already know from writing clean functions in general. Still, there are some control-structure specific concepts, that are covered in this document and course section.

Untitled

Prefer Positive Checks

This is a simple one. It can make sense to use positive wording in your if checks instead of negative wording.

Though - in my opinion at least - sometimes a short negative phrase is better than a constructed positive one.

Consider this example:

def is_empty(content):
    return not content

def has_content(content):
    return bool(content)

# Example usage
blog_content = ""

if is_empty(blog_content):
    # Raise an error or handle the case of empty content
    raise ValueError('Blog content is empty!')

if not has_content(blog_content):
    # Raise an error or handle the case of no content
    raise ValueError('Blog content has no content!')

The first snippet is quite readable and requires zero thinking.

The second snippet uses the ! operator to check for the opposite - slightly more thinking and interpretation is required from the reader.

Hence option #1 is preferrable. However, sometimes, I do prefer the negative version:

def is_open(transaction):
    return not transaction['isOpen']

def is_closed(transaction):
    return transaction['isClosed']

# Example usage
transaction_data = {'isOpen': True, 'isClosed': False}

if not is_open(transaction_data):
    # Raise an error or handle the case of a closed transaction
    raise ValueError('Transaction is not open!')

if is_closed(transaction_data):
    # Raise an error or handle the case of a closed transaction
    raise ValueError('Transaction is closed!')

On first sight, it looks like option #2 is better. And it generally might be. But what if we didn't just have 'Open' and 'Closed' transactions? What if we also had 'Unknown'?

def is_open(transaction):
    return not transaction['isOpen']

def is_closed(transaction):
    return transaction['isClosed']

def is_unknown(transaction):
    return transaction['isUnknown']

# Example usage
transaction_data = {'isOpen': True, 'isClosed': False, 'isUnknown': False}

if not is_open(transaction_data):
    # Raise an error or handle the case of a closed transaction
    raise ValueError('Transaction is not open!')

if is_closed(transaction_data) or is_unknown(transaction_data):
    # Raise an error or handle the case of a closed or unknown transaction
    raise ValueError('Transaction is closed or unknown!')