Знайомство з антипатернами
Антипатерни — повна протилежність патернам. Якщо патерни — це рецепти «як готувати смачно», то антипатерни — це список того, чого робити на кухні категорично не можна, якщо не хочете отруїти гостей.
Частиною практик гарного програмування є саме уникнення антипатернів. Не слід думати, що це суха теорія — це граблі, на які наступав кожен Senior-розробник. Хто поінформований, той озброєний!
Розглянемо класичну п'ятірку антипатернів:
- Магічні числа та рядки
- Божественний об'єкт (God Object)
- Передчасна оптимізація
- Винайдення велосипеда
- Винайдення квадратного колеса
Магічні числа та рядки
Магічне число — це константа (число або рядок), яка зустрічається в коді без пояснення її значення.
if user.status == 2: # Що таке 2? Адмін? Забанений? Мертвий?
do_something()
Коли в коді з'являються такі числа, програміст, який читатиме цей код за місяць (навіть якщо це ви самі), витратить години, намагаючись зрозуміти цей сакральний зміст.
Як лікувати в Python:
- Використовуйте константи зі зрозумілими іменами (у верхньому регістрі):
STATUS_BANNED = 2. - Використовуйте Enums (модуль
enum), який з'явився у Python 3.4. Це ідеальне рішення для статусів і типів.
God Object
Божественний об'єкт — це клас, який знає занадто багато, робить занадто багато і зберігає в собі майже всі дані застосунку. У Python цей антипатерн часто мутує в God Module.
Типовий приклад студента — файл views.py або utils.py на 3000 рядків, у якому перемішані:
- Реєстрація користувачів
- Відправка email
- Генерація PDF-звітів
- Парсинг Excel
Такий код неможливо тестувати (доводиться мокати половину всесвіту), складно читати та страшно змінювати.
Лікування: розбивайте завдання на підзавдання (Single Responsibility Principle). Логіку роботи з поштою — у services/email.py, звіти — у services/reports.py.
Передчасна оптимізація
Передчасна оптимізація — це спроба зробити код швидшим до того, як ви довели, що він працює повільно.
Дональд Кнут сказав: «Передчасна оптимізація — корінь усіх бід».
Пітоністи-початківці часто витрачають години, намагаючись переписати зрозумілий цикл for на складну конструкцію з map/filter/lambda, бо «десь чули, що це швидше». У результаті код стає нечитабельним, а виграш становить 0.001 секунди.
Python-way:
- Спочатку пишіть чистий і читабельний код.
- Якщо код працює повільно — використовуйте профайлер (модуль
cProfileабо інструменти в PyCharm). - Знаходьте вузьке місце (часто це зайвий запит до БД, а не Python-код) і оптимізуйте тільки його.
Винайдення велосипеда
Сенс цього антипатерна: програміст пише власне рішення завдання, для якого вже існує готова, перевірена та оптимізована бібліотека.
Python славиться своєю філософією «Батарейки в комплекті» та величезним репозиторієм PyPI.
Приклади «велосипедів»:
- Писати свій парсер CSV замість
import csv. - Писати свої регулярні вирази для перевірки email замість використання
pydantic.EmailStr. - Писати свій клієнт для HTTP-запитів на сокетах замість
import requests.
Ваше самописне рішення майже напевно міститиме більше багів і працюватиме повільніше, ніж бібліотека, яку спільнота полірує роками.
Винайдення велосипеда з квадратними колесами
Це посилена версія попереднього пункту. Ви не просто винайшли велосипед, ви винайшли поганий велосипед.
Це подвійна втрата часу: спочатку ви пишете криве рішення, а потім витрачаєте тижні на його лагодження та підтримку. У результаті все одно доводиться викидати код і брати готову бібліотеку.
Dependency Injection
Якщо «God Object» — це хвороба, то Dependency Injection — це ліки. Це патерн, який рятує проєкти від перетворення на «спагеті-код».
Проблема жорсткого зв'язку:
class UserService:
def __init__(self):
# ПОМИЛКА: Сервіс сам створює підключення до БД.
# Тепер ви не зможете протестувати цей сервіс без реальної бази!
self.db = PostgresDB("localhost", 5432)
Рішення (DI):
class UserService:
def __init__(self, db):
# ПРАВИЛЬНО: Залежність (db) передається ззовні.
# У тестах ви зможете передати сюди «фейкову» базу (Mock).
self.db = db
Приклад у FastAPI:
Якщо ви працювали з FastAPI, ви вже використовуєте потужну систему DI. Механізм Depends робить усю брудну роботу за вас:
def read_users(db: Session = Depends(get_db)): ...
Фреймворк сам знайде, як створити підключення до БД, і «впровадить» його у вашу функцію. Це робить код чистим, модульним і таким, що легко тестується.
Хронологія технологій
Щоб ви розуміли масштаб досвіду, на який спираєтеся:
- Мови та стандарти:
- SQL — 52 роки (1974)
- Python — 35 років (1991)
- HTTP — 35 років (1991)
- Java — 31 рік (1995)
- Інструменти Python-розробника:
- Django — 21 рік (2005)
- SQLAlchemy — 20 років (2006)
- Git — 21 рік (2005)
- Docker — 13 років (2013)
- FastAPI — 7 років (2018)
- Операційні системи:
- Unix — 57 років (1969)
- Linux — 35 років (1991)
Коли вам здається, що ви придумали «унікальну» архітектуру для зберігання налаштувань або роботи з БД — скоріш за все, ви просто не дочитали документацію до інструмента, якому вже 20 років.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ