Home / Programmeren / Best Practices / Softwareontwikkeling / Deel 6: Veelvoorkomende anti-patronen in softwareontwikkeling

Deel 6: Veelvoorkomende anti-patronen in softwareontwikkeling

Luca Bravo

Er zijn verschillende veelvoorkomende anti-patronen in softwareontwikkeling die je moet vermijden.

Gebruik van if-else voor een `Boolean Return`: Het schrijven van onnodige conditionele statements in plaats van simpelweg de Booleaanse expressie direct terug te geven. In het goede voorbeeld wordt de Boolean expressie direct teruggegeven, wat de code eenvoudiger en leesbaarder maakt.

# 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`: Het gebruik van veranderlijke standaardargumenten kan leiden tot onverwacht gedrag. In het goede voorbeeld wordt een nieuwe lijst aangemaakt als er geen lijst wordt doorgegeven. Dit voorkomt dat de standaardlijst wordt gedeeld tussen aanroepen van de functie.

# 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`: Het niet gebruiken van idiomatische constructies wanneer dat gepast is. In het goede voorbeeld wordt een list comprehension gebruikt, wat de code korter en duidelijker maakt.

# 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`: Het vertrouwen op globale variabelen in plaats van gegevens door functieargumenten of class-attributen door te geven. In het goede voorbeeld wordt de waarde als argument doorgegeven, wat de functie flexibeler en beter testbaar maakt.

# 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

Geen gebruik maken van virtuele omgevingen: Het niet isoleren van projectafhankelijkheden kan leiden tot afhankelijkheidsconflicten. In het goede voorbeeld wordt een virtuele omgeving aangemaakt en geactiveerd. Dit zorgt voor een schone en geïsoleerde omgeving voor het project. Dit voorkomt dat afhankelijkheden van verschillende projecten elkaar beïnvloeden.

Slecht voorbeeld:
Bij het installeren van pakketten zonder een virtuele omgeving, kunnen verschillende projecten afhankelijk zijn van verschillende versies van dezelfde bibliotheek, wat leidt tot conflicten.

Goed voorbeeld:
Door gebruik te maken van een virtuele omgeving, zoals met venv in Python, kunnen afhankelijkheden per project worden beheerd zonder conflicten.
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: Dit verwijst naar een object dat te veel verantwoordelijkheden heeft en daardoor moeilijk te begrijpen en te onderhouden is.

# 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: Dit is een term die wordt gebruikt om code te beschrijven die slecht gestructureerd is en moeilijk te volgen.

# 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: Het herhalen van code door deze te kopiëren en plakken in plaats van herbruikbare functies of modules te maken.

# 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: Het gebruik van onduidelijke constante waarden in de code zonder uitleg of 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: Het creëren van een te complexe oplossing voor een eenvoudig probleem.

Slecht voorbeeld:

# 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): De neiging om bestaande oplossingen of bibliotheken te negeren en in plaats daarvan zelf iets te bouwen.

# 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: Het optimaliseren van code voordat het nodig is.

# 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: Het direct in de code opnemen van waarden die beter extern beheerd kunnen worden.

# 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: Een situatie waarin een module of klasse verantwoordelijkheden heeft die niet logisch met elkaar verbonden zijn.

# 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: Het schrijven van onduidelijke of complexe code en vervolgens vertrouwen op comments om de logica uit te leggen.

# 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

Heb je vragen of opmerkingen, laat het me weten!