Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое хороший код
Хороший код — это не просто код, который работает. Это код, который легко понять, поддерживать, тестировать и расширять. За 10+ лет разработки я выделил ключевые характеристики качественного кода.
1. Читаемость
Хороший код пишется для людей, не для компьютера. Компьютер просто выполняет инструкции.
# Плохо: непонятное имя переменной
def calc(x, y, z):
r = x * y + z / 2
return r if r > 0 else 0
# Хорошо: явное имя и назначение
def calculate_profit_margin(revenue, costs, discount):
profit = revenue - costs + discount / 2
return max(profit, 0)
Правила читаемости:
- Значимые имена переменных, функций, классов
- Функция делает одно, но делает хорошо
- Избегаешь вложенности более чем на 3 уровня
- Максимум 20-30 строк в функции (исключения редки)
2. Простота (KISS - Keep It Simple, Stupid)
Просто — не значит глупо. Это означает: не усложняй без необходимости.
# Плохо: оверинжиниринг
from abc import ABC, abstractmethod
class OperationFactory:
_operations = {}
@classmethod
def register(cls, name, operation):
cls._operations[name] = operation
@classmethod
def execute(cls, name, *args):
return cls._operations[name](*args)
class Add(ABC):
@abstractmethod
def execute(self, a, b):
pass
class AddImpl(Add):
def execute(self, a, b):
return a + b
OperationFactory.register('add', AddImpl().execute)
result = OperationFactory.execute('add', 2, 3)
# Хорошо: просто и понятно
def add(a, b):
return a + b
result = add(2, 3)
Когда нужна сложность? Только когда задача действительно требует её.
3. Тестируемость
Хороший код легко тестировать. Если код сложно тестировать — значит его архитектура плохая.
# Плохо: зависимость от внешних сервисов, сложно тестировать
def process_payment(amount):
api = PaymentAPI() # Захардкодено
api.charge(amount)
db = Database() # Захардкодено
db.save_transaction(amount)
# Хорошо: зависимости инъектируются
def process_payment(amount, payment_api, database):
payment_api.charge(amount)
database.save_transaction(amount)
# Тестирование с mock объектами
from unittest.mock import Mock
mock_api = Mock()
mock_db = Mock()
process_payment(100, mock_api, mock_db)
mock_api.charge.assert_called_once_with(100)
mock_db.save_transaction.assert_called_once_with(100)
4. DRY (Don't Repeat Yourself)
Если ты пишешь один и тот же код дважды — это плохо.
# Плохо: дублирование
def validate_email(email):
if '@' not in email or '.' not in email:
raise ValueError("Invalid email")
def validate_phone(phone):
if '+' not in phone or not phone[1:].isdigit():
raise ValueError("Invalid phone")
# Хорошо: общая функция
import re
def validate_format(value, pattern, error_msg):
if not re.match(pattern, value):
raise ValueError(error_msg)
validate_format(email, r'^[\w.-]+@[\w.-]+\.\w+$', "Invalid email")
validate_format(phone, r'^\+\d{10,}$', "Invalid phone")
5. SOLID Принципы
Single Responsibility (Единая ответственность):
# Плохо: класс делает всё
class User:
def create_user(self, data):
self.validate(data)
self.save_to_db(data)
self.send_email(data['email'])
self.log_event("User created")
# Хорошо: разделение ответственности
class User:
def __init__(self, validator, repository, notifier, logger):
self.validator = validator
self.repository = repository
self.notifier = notifier
self.logger = logger
def create(self, data):
self.validator.validate(data)
user = self.repository.save(data)
self.notifier.send_welcome_email(user)
self.logger.info(f"User {user.id} created")
return user
Open/Closed (Открыто для расширения, закрыто для модификации):
# Плохо: нужно изменять функцию при добавлении нового типа
def calculate_discount(price, user_type):
if user_type == 'premium':
return price * 0.9
elif user_type == 'vip':
return price * 0.8
elif user_type == 'regular':
return price
# Хорошо: расширяемо без изменений
class DiscountStrategy:
def apply(self, price):
raise NotImplementedError
class PremiumDiscount(DiscountStrategy):
def apply(self, price):
return price * 0.9
class VIPDiscount(DiscountStrategy):
def apply(self, price):
return price * 0.8
def calculate_discount(price, strategy: DiscountStrategy):
return strategy.apply(price)
6. Обработка ошибок
Хороший код предусматривает ошибки и обрабатывает их правильно.
# Плохо: бледная обработка ошибок
try:
result = 1 / 0
except:
pass # Игнорируем всё
# Хорошо: обработка конкретных ошибок
try:
result = 1 / divisor
except ZeroDivisionError:
logger.error("Division by zero", extra={"divisor": divisor})
return None
except TypeError:
logger.error("Invalid type for division", extra={"type": type(divisor)})
raise
7. Производительность
Хороший код оптимален, но не оптимизирован раньше времени.
# Плохо: преждевременная микро-оптимизация
def search(items, target):
# Очень быстро на малых списках, но сложно читать
return next((i for i, x in enumerate(items) if x == target), -1) if items else -1
# Хорошо: понятно и достаточно быстро
def search(items, target):
try:
return items.index(target)
except ValueError:
return -1
# Оптимизируй, когда профилирование покажет проблему
import cProfile
cProfile.run('search(large_list, target)') # Профилируй перед оптимизацией
8. Документация
Хороший код самодокументируется, но иногда нужны комментарии.
# Плохо: ненужные комментарии
x = 5 # устанавливаем x в 5
for i in range(x): # цикл от 0 до x
print(i) # выводим i
# Хорошо: нет комментариев, но код понятен
max_retries = 5
for attempt in range(max_retries):
print(attempt)
# Хорошо: комментарии объясняют ПОЧЕМУ, не ЧТО
def calculate_hash(data):
# MurmurHash3 используем для лучшей распределении ключей в hash table
# по сравнению со встроенным hash() который может быть медленнее
return murmurhash3(data)
9. Версионирование и история
Хороший код имеет историю изменений с понятными commit сообщениями.
# Плохо
git commit -m "fixed stuff"
git commit -m "updates"
# Хорошо
git commit -m "fix: handle null pointers in payment processing
When payment API returns null, system crashed.
Now we validate response and return meaningful error.
Fixes #123"
10. Type Hints (в Python)
Хороший Python код использует type hints для безопасности.
# Плохо: неясно какие типы
def process(data):
return len(data) > 0
# Хорошо: явные типы
def process(data: list[str]) -> bool:
return len(data) > 0
# С mypy проверкой типов
from typing import Optional
def find_user(user_id: int) -> Optional[User]:
# ...
pass
11. Следование стилю проекта
Хороший код согласуется с существующим codebase.
# Если проект использует black для форматирования
python -m black myfile.py
# Если проект использует ruff для linting
python -m ruff check myfile.py
# Если проект имеет type hints
mypy myfile.py
12. Модульность
Хороший код разбивается на маленькие, переиспользуемые модули.
# Плохо: монолитный скрипт
api.py (5000 строк, всё в одном файле)
# Хорошо: модульная структура
api/
__init__.py
models/
user.py
post.py
routes/
auth.py
posts.py
services/
user_service.py
post_service.py
middleware/
auth.py
logging.py
Практические метрики хорошего кода
- Cyclometric Complexity (сложность циклов) < 10 — хорошо
- Test Coverage > 80% — минимум для production
- Lines of Code в функции < 30 — идеал
- Code Duplication < 5% — хорошо
- Comment Ratio 10-20% — достаточно
Инструменты для контроля качества
# Python: статический анализ
mypy myfile.py # Type checking
pylint myfile.py # Лinting
ruff check myfile.py # Fast linting
black myfile.py # Форматирование
# Тестирование
pytest tests/ --cov # Tests + coverage
# Профилирование
python -m cProfile myapp.py
Заключение
Хороший код — это баланс между:
- Читаемостью (люди) и производительностью (компьютеры)
- Простотой (сейчас) и расширяемостью (будущее)
- Быстротой разработки (сроки) и качеством (поддержка)
Лучший способ писать хороший код — постоянно читать чужой код хороших проектов и учиться от опытных разработчиков.