Home / Programming / Best Practices / Software development / Part 6: Common Anti-Patterns in Software Development

Part 6: Common Anti-Patterns in Software Development

Luca Bravo

There are several common anti-patterns in software development that you should avoid.

Using if-else for a Boolean Return: Writing unnecessary conditional statements instead of simply returning the Boolean expression directly. In the good example, the Boolean expression is returned directly, making the code simpler and more readable.

# Slecht voorbeeld
def is_positive(number):
    if number > 0:
        return True
    else:
        return False
# Goed voorbeeld
def is_positive(number):
    return number > 0

Overuse of Mutable default arguments: Using mutable default arguments can lead to unexpected behavior. In the good example, a new list is created when no list is passed. This prevents the default list from being shared between function calls.

# Slecht voorbeeld
def append_to_list(value, my_list=[]):
    my_list.append(value)
    return my_list
# Goed voorbeeld
def append_to_list(value, my_list=None):
    if my_list is None:
        my_list = []
    my_list.append(value)
    return my_list

Ignoring Programming idioms: Not using idiomatic constructs when appropriate. In the good example, a list comprehension is used, making the code shorter and clearer.

# Slecht voorbeeld
def get_even_numbers(numbers):
    even_numbers = []
    for number in numbers:
        if number % 2 == 0:
            even_numbers.append(number)
    return even_numbers
# Goed voorbeeld
def get_even_numbers(numbers):
    return [number for number in numbers if number % 2 == 0]

Overuse of Global variables: Relying on global variables instead of passing data through function arguments or class attributes. In the good example, the value is passed as an argument, making the function more flexible and easier to test.

# Slecht voorbeeld
global_var = 10

def add_to_global(value):
    return global_var + value
# Goed voorbeeld
def add_to_value(value, base_value):
    return base_value + value

result = add_to_value(5, 10)  # Geeft 15 terug

Not using virtual environments: Not isolating project dependencies can lead to dependency conflicts. In the good example, a virtual environment is created and activated. This ensures a clean and isolated environment for the project, preventing dependencies from different projects from interfering with each other.

Bad example:
When installing packages without a virtual environment, different projects may depend on different versions of the same library, leading to conflicts.

Good example:
By using a virtual environment, such as with venv in Python, dependencies can be managed per project without conflicts.
python -m venv myenv
source myenv/bin/activate  # Voor Unix-achtige systemen
myenv\Scripts\activate  # Voor Windows

pip install requests==2.25.1  # Installeert alleen in de virtuele omgeving

God object: This refers to an object that has too many responsibilities, making it difficult to understand and maintain.

# Slecht voorbeeld
class Application:
    def __init__(self):
        self.database = Database()
        self.user_interface = UserInterface()
        self.network = Network()

    def run(self):
        self.database.connect()
        self.user_interface.display()
        self.network.fetch_data()
# Goed voorbeeld
class Application:
    def __init__(self, database, user_interface, network):
        self.database = database
        self.user_interface = user_interface
        self.network = network

    def run(self):
        self.database.connect()
        self.user_interface.display()
        self.network.fetch_data()

app = Application(Database(), UserInterface(), Network())
app.run()

Spaghetti code: This is a term used to describe code that is poorly structured and hard to follow.

# Slecht voorbeeld
def process_data(data):
    if data:
        for item in data:
            if item['status'] == 'active':
                print(item['name'])
            else:
                if item['status'] == 'inactive':
                    print(item['name'] + " is inactive")
                else:
                    print("Unknown status")
# Goed voorbeeld
def process_data(data):
    for item in data:
        handle_item(item)

def handle_item(item):
    if item['status'] == 'active':
        print(item['name'])
    elif item['status'] == 'inactive':
        print(item['name'] + " is inactive")
    else:
        print("Unknown status")

Copy-Paste programming: Repeating code by copying and pasting instead of creating reusable functions or modules.

# Slecht voorbeeld
def calculate_area_circle(radius):
    return 3.14 * radius * radius

def calculate_area_square(side):
    return side * side

def calculate_area_rectangle(length, width):
    return length * width

# Herhaling van de formule voor cirkel
def calculate_area_circle_v2(radius):
    return 3.14 * radius * radius
# Goed voorbeeld
def calculate_area_circle(radius):
    return 3.14 * radius * radius

def calculate_area_square(side):
    return side * side

def calculate_area_rectangle(length, width):
    return length * width

# Herbruikbare functie voor cirkel
def calculate_area_circle_v2(radius):
    return calculate_area_circle(radius)

Magic numbers: Using unclear constant values in the code without explanation or context.

# Slecht voorbeeld
def calculate_discount(price):
    return price * 0.2  # 20% korting
# Goed voorbeeld
DISCOUNT_RATE = 0.2

def calculate_discount(price):
    return price * DISCOUNT_RATE

Over-engineering: Creating an overly complex solution for a simple problem.

Bad example:

# Slecht voorbeeld
class ComplexCalculator:
    def add(self, a, b):
        return a + b

    def subtract(self, a, b):
        return a - b

    def multiply(self, a, b):
        return a * b

    def divide(self, a, b):
        return a / b

# Te veel complexiteit voor eenvoudige berekeningen
calc = ComplexCalculator()
result = calc.add(5, 3)
# Goed voorbeeld
def add(a, b):
    return a + b

result = add(5, 3)

Not Invented Here (NIH): The tendency to ignore existing solutions or libraries and build something yourself instead.

# Slecht voorbeeld
class CustomList:
    def __init__(self):
        self.items = []

    def add(self, item):
        self.items.append(item)

    def get(self, index):
        return self.items[index]
# Goed voorbeeld
my_list = []
my_list.append("item")
print(my_list[0])

Premature optimization: Optimizing code before it is necessary.

# Slecht voorbeeld
def calculate_sum(numbers):
    total = 0
    for number in numbers:
        total += number
    return total
# Goed voorbeeld
def calculate_sum(numbers):
    return sum(numbers)

Hardcoding: Embedding values directly in the code that should be managed externally.

# Goed voorbeeld
def connect_to_database():
    connection = create_connection("localhost", "root", "password", "my_database")
# Goed voorbeeld
def connect_to_database(host, user, password, database):
    connection = create_connection(host, user, password, database)

# Gebruik van variabelen of configuratiebestanden
connect_to_database("localhost", "root", "password", "my_database")

Lack of cohesion: A situation where a module or class has responsibilities that are not logically connected.

# Slecht voorbeeld
class Utility:
    def calculate_area_circle(self, radius):
        return 3.14 * radius * radius

    def print_message(self, message):
        print(message)
# Goed voorbeeld
class Circle:
    def __init__(self, radius):
        self.radius = radius

    def area(self):
        return 3.14 * self.radius * self.radius

class MessagePrinter:
    @staticmethod
    def print_message(message):
        print(message)

Over-reliance on comments: Writing unclear or complex code and then relying on comments to explain the logic.

# Slecht voorbeeld
def calculate_discount(price):
    # Deze functie berekent de korting
    return price * 0.2  # 20% korting
# Goed voorbeeld
def calculate_discount(price, discount_rate=0.2):
    return price * discount_rate

Do you have questions or comments? Let me know!