Модуль 36

Типові помилки та антипатерни

Ось готовий урок, згенерований за твоїм майстер-промптом. Він орієнтований на початківців у програмуванні (на прикладі Python, оскільки це мова курсу CS50, але принципи універсальні).


🎓 CS50: Типові помилки та антипатерни

(Або: Як не писати код, за який вам буде соромно через пів року)


1. 🔥 Вступ: Чому ваш код працює, але "пахне"?

Уявіть, що ви вирішили приготувати вечерю. Ви берете всі продукти з холодильника — м'ясо, молоко, овочі, шоколад — кидаєте їх в одну велику каструлю і варите 3 години. У результаті ви отримуєте... ну, технічно, це їжа. Вона гаряча. Вона має калорії. Ви навіть не отруїтесь.

Але чи захочете ви це їсти? І головне — якщо ви захочете додати солі, як ви це зробите, не зіпсувавши смак шоколаду, який вже розчинився?

У програмуванні ми називаємо це "Спагеті-код" або Антипатерни.

Часто новачки думають: "Головне, щоб програма запустилася і видала правильну відповідь". Але дозвольте запитати: * Скільки часу ви витратите завтра, щоб змінити одну маленьку деталь у цьому хаосі? * Чи зрозуміє ваш колега (або ви самі через тиждень), що відбувається у вашому коді?

Мотивація: Сьогодні ми не просто вчимося писати код, який працює. Ми вчимося писати код, який живе. Ми розглянемо типові пастки, у які потрапляють 90% новачків, і навчимося їх оминати. Це різниця між тим, щоб скласти намет у дворі, і тим, щоб збудувати хмарочос.


2. 🧠 Теоретична база: Що таке "Антипатерн"?

Давайте розберемося з термінологією, але без нудних визначень з підручників.

🔹 Помилка (Bug) vs Антипатерн

  • Помилка (Bug): Ви написали код, і програма "впала" (Crash) або видала 2 + 2 = 5. Це як дірка в колесі — їхати не можна.
  • Антипатерн: Програма працює правильно. Вона видає 4. Але код написаний так криво, заплутано або неефективно, що будь-яка спроба його покращити призведе до катастрофи. Це як їхати на машині з квадратними колесами — технічно ви рухаєтесь, але це боляче.

🔹 Що відбувається "під капотом"?

Комп'ютеру (інтерпретатору або компілятору) здебільшого байдуже, наскільки красиво ви пишете. Для процесора змінні x, data_list та temp_var_123 — це просто адреси в пам'яті. Він виконає будь-яку інструкцію.

Антипатерни — це проблема не для машини, а для людини. Коли ви порушуєте принципи чистого коду, ви збільшуєте так зване когнітивне навантаження. Ваш мозок мусить тримати в оперативній пам'яті занадто багато деталей одночасно, і в якийсь момент ви неминуче помилитесь.

📌 Що треба запам'ятати залізно:

  1. DRY (Don't Repeat Yourself): Не повторюй себе. Якщо ви скопіювали шматок коду більше двох разів — це сигнал тривоги.
  2. Магічні числа: Числа в коді без пояснень — це зло.
  3. KISS (Keep It Simple, Stupid): Не ускладнюйте там, де можна зробити просто.

3. 🧪 Приклади: Від жаху до краси

Давайте подивимось на код. Я покажу вам, як не треба, а ви спробуйте подумати, чому це погано, перш ніж читати пояснення.

Приклад 1: Магічні числа 🧙‍♂️

❌ Як це виглядає у новачка:

def calculate_salary(hours):
    return hours * 20 * 0.8

Запитання до вас: Що таке 20? А що таке 0.8? Якщо податок зміниться, де ви будете шукати це число?

✅ Як це робить профі:

HOURLY_RATE = 20
TAX_RATE = 0.2  # 20% податку

def calculate_salary(hours):
    gross_pay = hours * HOURLY_RATE
    net_pay = gross_pay * (1 - TAX_RATE)
    return net_pay

Пояснення: Тепер код читається як англійська мова. Ми винесли константи. Якщо ставка зміниться, ми змінимо її в одному місці зверху, а не шукатимемо по всьому файлу.


Приклад 2: Copy-Paste (Порушення DRY) 🐑🐑🐑

❌ Ситуація: Треба привітати трьох користувачів.

print("Hello, Mike!")
print("Welcome to our system.")
print("---")

print("Hello, Sarah!")
print("Welcome to our system.")
print("---")

print("Hello, John!")
print("Welcome to our system.")
print("---")

Запитання: Що, якщо текст привітання зміниться на "Hi" замість "Hello"? Вам доведеться правити це в трьох місцях. А якщо користувачів 1000?

✅ Використовуємо функції та цикли:

def greet_user(name):
    print(f"Hello, {name}!")
    print("Welcome to our system.")
    print("---")

users = ["Mike", "Sarah", "John"]

for user in users:
    greet_user(user)

Пояснення: Ми створили абстракцію (функцію). Тепер логіка привітання живе в одному місці. Це і є принцип DRY.


Приклад 3: "Божественна функція" (God Object) 🦖

Це коли одна функція робить ВСЕ: читає файл, рахує математику, відправляє емейл і варить каву.

❌ Антипатерн:

def process_data():
    # 50 рядків коду для зчитування файлу
    # ...
    # 30 рядків для складних обчислень
    # ...
    # 20 рядків для збереження результату в базу

✅ Single Responsibility Principle (Принцип єдиної відповідальності): Розбийте це на три функції: read_file(), calculate_stats(), save_to_db(). Головна функція просто керуватиме ними, як диригент оркестром.


4. 🛠 Практична частина

Час "забруднити руки" кодом! Спробуйте вирішити ці завдання.

🔹 Завдання 1: Полювання на відьом (Магічні числа)

У цьому коді перевіряється доступ користувача.

if age > 18 and status == 1:
    print("Access granted")

Завдання: Перепишіть код, замінивши числа 18 і 1 на іменовані константи зі зрозумілими назвами.

🔹 Завдання 2: Рефакторинг (DRY)

Ви бачите цей код:

area1 = 3.14 * 5 * 5
print(f"Circle 1 area: {area1}")

area2 = 3.14 * 10 * 10
print(f"Circle 2 area: {area2}")

Завдання: Створіть функцію calculate_circle_area(radius), щоб уникнути повторень, і використайте її.

🔹 Завдання 3: Виправлення логіки (Міні-кейс)

Студент написав функцію, яка має повертати True, якщо число парне, і False, якщо непарне.

def is_even(n):
    if n % 2 == 0:
        return True
    else:
        # Тут нічого немає
        pass

Проблема: Якщо число непарне, функція поверне None (за замовчуванням у Python), а не False. Завдання: Виправте функцію так, щоб вона завжди повертала булеве значення. А ще краще — скоротіть її до одного рядка!

🔹 Завдання 4: А що, якщо...

Уявіть, що ви використовуєте список імен names = ["Anna", "Bob"]. Ви звертаєтесь до елемента names[2]. Запитання: Що станеться? Як професійно уникнути падіння програми в цьому місці? (Підказка: перевірка довжини або обробка помилок try-except).


5. 💡 Мислення як у розробника

Як відрізнити новачка від сеньйора, просто глянувши на екран?

Новачок думає: * "Ура! Воно запустилося!" (і одразу біжить комітити код). * "Я напишу це в один рядок, щоб виглядати розумним хакером". * Копіює шматки коду зі StackOverflow, не розуміючи, як вони працюють.

Досвідчений розробник думає: * "Чи зрозумію я цей код, якщо мене розбудять о 3-й ночі через пів року?" * "Що буде, якщо сюди прийдуть некоректні дані? Програма впаде чи повідомить про помилку?" * "Чи можу я використати цей шматок коду повторно в іншому проєкті?"

Порада від Malan-а: Пишіть код так, ніби людина, яка буде його супроводжувати — це буйний психопат, який знає, де ви живете. Пишіть чисто. Пишіть зрозуміло.


6. 🧩 Підсумок

Сьогодні ми зрозуміли, що програмування — це не лише про синтаксис. Це про дизайн і гігієну мислення.

Ми навчилися: 1. Уникати магічних чисел (давати імена константам). 2. Дотримуватися принципу DRY (не копіювати код). 3. Розбивати великі задачі на маленькі функції.

Що ви тепер вмієте? Ви вмієте бачити "брудний" код і знаєте, як його "відмити". Ви перейшли від простого написання команд до інженерії.

📢 Тизер наступного уроку: Тепер, коли ми вміємо писати чистий код, виникає питання: а як нам зберігати величезні масиви даних і швидко знаходити в них інформацію? У наступній лекції ми заглянемо у світ Алгоритмів пошуку та сортування. Ви дізнаєтесь, чому розірвати телефонний довідник навпіл — це найкращий спосіб знайти потрібне ім'я!

Побачимось! 👋