Модуль 35

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

Чудовий запит! Як би сказав Девід Малан: "This is CS50!" 🖐️🎤

Сьогодні ми не просто пишемо код, який працює. Ми вчимося писати код, який живе.

Ось твій урок.


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

(Або: Чому ваш код працює, але його хочеться спалити)


1. 🔥 Вступ: проблема та мотивація

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

Ви якось примудряєтеся зварити з цієї купи страву. Вона смачна? Можливо. Ви нагодували гостей? Так. Але чи зможете ви приготувати це знову завтра? Чи зможете ви знайти сіль, не перериваючи всю купу сміття?

У програмуванні це називається "Спагеті-код" (іронічно, правда?).

Питання до вас: Чи доводилося вам відкривати свій старий код (написаний місяць тому) і витрачати 20 хвилин просто на те, щоб зрозуміти: «Що тут взагалі відбувається?»?

Без розуміння антипатернів (типових поганих рішень) ви стаєте будівельником, який будує хмарочос із скотчу та картону. Він стоїть, поки немає вітру. Але в реальному IT "вітер" (зміни вимог, нові фічі) дме постійно.

Сьогодні ми навчимося бачити ці проблеми до того, як вони стануть катастрофою.


2. 🧠 Теоретична база (без сухої академічності)

Давайте розберемося з термінологією. Тут все просто.

  • Баг (Bug) — це коли код не працює. Програма падає, видає помилку або 2+2=5.
  • Антипатерн (Anti-pattern) — це коли код працює, але написаний так погано, що його підтримка перетворюється на пекло. Це «міна уповільненої дії».
  • Code Smell («Запашок» коду) — це сигнал. Сам по собі код ще працює, але він уже «попахує» проблемами.

Як це працює «під капотом»?

Комп’ютеру (процесору) абсолютно байдуже, наскільки красиво ви написали код. Для нього x = 5 і users_count_in_active_session = 5 — це одне й те саме: просто комірка в пам'яті.

АЛЕ! Код пишеться не для машин. Код пишеться для людей. Для ваших колег і для "майбутнього вас".

🔑 Що треба запам’ятати (Золоті правила):

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

3. 🧪 Приклади (від простого до реального)

Давайте подивимося на код. Я буду писати на псевдокоді (схожому на Python/JS), щоб зрозуміли всі.

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

Уявіть, ви пишете магазин.

❌ Поганий код:

price = 100
final_price = price * 1.2  # <--- Що таке 1.2?

Питання: Як ви думаєте, що станеться, якщо через рік податок зміниться, а у вас це число 1.2 розкидане по 50 файлах проєкту?

✅ Хороший код:

TAX_RATE = 1.2  # Константа з чіткою назвою

price = 100
final_price = price * TAX_RATE

Пояснення: Тепер ми змінюємо податок в одному місці, і він оновлюється всюди. Ми дали числу ім'я.


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

Ви хочете привітати трьох користувачів.

❌ Поганий код:

print("Привіт, Олексій! Твій баланс: 100")
send_email("alex@mail.com", "Ласкаво просимо")

print("Привіт, Марія! Твій баланс: 200")
send_email("maria@mail.com", "Ласкаво просимо")

print("Привіт, Дмитро! Твій баланс: 50")
send_email("dima@mail.com", "Ласкаво просимо")

Що ви очікуєте? Це працює. Але уявіть, що бос каже: "Змініть текст листа на 'Вітаємо в системі'". Вам доведеться правити це в трьох місцях. А якщо користувачів 1000?

✅ Хороший код:

def greet_user(name, email, balance):
    print(f"Привіт, {name}! Твій баланс: {balance}")
    send_email(email, "Вітаємо в системі") # Змінили тут — змінилось у всіх

# Використання
greet_user("Олексій", "alex@mail.com", 100)
greet_user("Марія", "maria@mail.com", 200)

Приклад 3: God Object (Божественний об'єкт) 🏛️

Це коли одна функція робить ВСЕ.

❌ Поганий код:

def process_order(order):
    # 1. Перевіряє наявність товару в базі
    # 2. Знімає гроші з картки
    # 3. Відправляє email клієнту
    # 4. Друкує накладну на принтері складу
    # 5. Оновлює статистику продажів
    ... 200 рядків коду ...

Чому це погано? Якщо зламається принтер, у вас перестане працювати оплата карткою! Усе пов'язане.

✅ Хороший код: Розбиваємо на маленькі незалежні функції (check_stock, charge_card, send_email).


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

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

Завдання 1: Полювання на відьом (Magic Numbers) Знайди помилку в цьому коді і виправ її, використовуючи константу.

# Розрахунок площі кола
radius = 5
area = 3.14159 * radius * radius

Завдання 2: Знешкодити "Макаронного монстра" (Nested loops) У вас є код, який виглядає як драбина (дуже велика вкладеність if в if). Це складно читати. Завдання: Перепишіть логіку, використовуючи "Early Return" (повернення результату раніше).

def check_access(user):
    if user:
        if user.is_active:
            if user.has_permission:
                return "Доступ дозволено"
            else:
                return "Немає прав"
        else:
            return "Користувач неактивний"
    else:
        return "Користувача не знайдено"

Підказка: Спробуйте перевіряти негативні умови спочатку (if not user: return ...).

Завдання 3: Іменування змінних Перейменуйте змінні так, щоб код став зрозумілим без коментарів.

d = 7  # Кількість днів
p = 24 # Кількість годин
t = d * p # Всього годин

Завдання 4: Міні-кейс "А що, якщо..." Ви написали функцію, яка зберігає дані у текстовий файл .txt. Ситуація: Замовник просить тепер зберігати дані не в файл, а в базу даних. Питання: Якщо ваша логіка збереження "зашита" (hardcoded) глибоко всередині бізнес-логіки, наскільки боляче буде це змінювати? Як би ви спроектували це від початку, щоб зміна формату збереження зайняла 5 хвилин?


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

Чим відрізняється новачок від сеньйора?

👶 Новачок думає: * «Ура, воно запустилося!» * «Не чіпай, поки працює.» * «Назву змінну a1, a2, я ж пам’ятаю, що це.»

😎 Досвідчений розробник думає: * «Цей код мені доведеться читати через пів року. Чи не захочу я виколоти собі очі?» * «Що буде, якщо дані прийдуть пустими?» * «Чи можу я виділити цей шматок в окрему функцію, щоб використати його десь ще?»

💡 Порада з практики: Найкращий код — це той, який не треба писати. Але якщо пишете — уявіть, що підтримувати ваш код буде маніяк, який знає, де ви живете. Пишіть чисто!


6. 🧩 Підсумок

Отже, що ми сьогодні поклали в нашу «валізу знань»?

  1. Код має бути читабельним. Ми пишемо для людей.
  2. Ніякої магії. Усі числа та дивні значення виносимо в константи.
  3. Не повторюємось (DRY). Якщо бачиш Ctrl+C / Ctrl+V — зупинись і напиши функцію.
  4. Антипатерни — це технічний борг. Чим більше їх сьогодні, тим важче "платити по кредиту" завтра.

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

🔜 У наступній серії: Ми навчилися писати чисто, але як переконатися, що наш код дійсно працює правильно у всіх ситуаціях? Наступна тема — Тестування: як спати спокійно, поки ваш код працює на сервері.

Це був CS50! 🖐️