Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Как относишься к ошибкам?
Этот вопрос о профессиональной зрелости разработчика. Я расскажу о правильном отношении к ошибкам в контексте профессиональной разработки.
Мой подход к ошибкам
1. Ошибки — это нормально и необходимо
Если вы не делаете ошибок, значит вы не решаете сложные проблемы. Ошибки — это:
- Часть процесса обучения — когда я делаю ошибку, я узнаю что-то новое
- Индикатор границ знания — ошибка показывает, где нужно улучшить навыки
- Возможность для улучшения — неправильно обработанные ошибки приводят к падению production
# Ошибка в коде — это нормально
try:
result = 10 / 0 # ZeroDivisionError
except ZeroDivisionError:
print("Ошибка помогла мне добавить валидацию")
2. Профилактика важнее лечения
Вместо того чтобы ждать когда пользователи обнаружат баги, я предотвращаю их:
# Плохо — жду ошибку
def divide(a, b):
return a / b # Может упасть на b=0
# Хорошо — предотвращаю ошибку
def divide(a, b):
if b == 0:
raise ValueError("Делитель не может быть нулём")
return a / b
# Отлично — типизирую и валидирую
from pydantic import BaseModel, field_validator
class DivideRequest(BaseModel):
a: float
b: float
@field_validator('b')
@classmethod
def b_not_zero(cls, v):
if v == 0:
raise ValueError('b cannot be 0')
return v
def divide(request: DivideRequest) -> float:
return request.a / request.b
3. Тестирование — защита от ошибок
# Написание тестов для потенциальных ошибок
import pytest
class TestCalculator:
def test_divide_normal(self):
assert divide(10, 2) == 5
def test_divide_by_zero(self):
with pytest.raises(ValueError):
divide(10, 0)
def test_divide_negative(self):
assert divide(-10, 2) == -5
def test_divide_floats(self):
assert divide(10.5, 2.1) == pytest.approx(5.0)
Я пишу тесты не после кода, а ДО кода (TDD). Это снижает количество ошибок в 2-3 раза.
4. Обработка ошибок должна быть информативной
# ❌ Плохая обработка ошибок
try:
process_data()
except Exception:
pass # Молча падает
# ❌ Неинформативная
try:
response = requests.get(api_url)
except Exception as e:
print(f"Error: {e}")
return None
# ✅ Правильная обработка
import logging
logger = logging.getLogger(__name__)
try:
response = requests.get(api_url, timeout=5)
response.raise_for_status()
except requests.Timeout:
logger.error(f"API timeout: {api_url}", exc_info=True)
raise # Пробрасываем выше, не молчим
except requests.ConnectionError as e:
logger.error(f"API connection error: {api_url}", exc_info=True)
raise
except Exception:
logger.exception("Unexpected error fetching API")
raise
5. Быстрое обнаружение ошибок
# Fail Fast — понять ошибку как можно раньше
def process_user(user_data: dict) -> User:
# Валидируем входные данные сразу
if not user_data.get("name"):
raise ValueError("Name is required") # Fail immediately
if not user_data.get("email"):
raise ValueError("Email is required") # Fail immediately
# Только потом обрабатываем
user = User(**user_data)
return user
# Вместо этого, где ошибка обнаружится позже
def bad_process(user_data):
user = User() # Не провалится здесь
user.name = user_data.get("name") # Может быть None
if user.name is None: # Ошибка найдётся позже
raise ValueError()
6. Post-mortem (разбор полётов)
Когда ошибка попадает в production, я:
# Post-mortem анализ
"""
1. ЧТО случилось?
- Payment service вернул 500 ошибку
- Пользователи не смогли оплатить заказы
2. ПОЧЕМУ это случилось?
- Не проверили response.status_code
- Не было retry логики
- Не было мониторинга
3. КАК ИСПРАВИТЬ?
- Добавить валидацию response
- Добавить retry с backoff
- Добавить alert в Sentry
4. КАК ПРЕДОТВРАТИТЬ?
- Код review должен проверять error handling
- Тесты для API failures
- Staging тестирование перед production
"""
7. Культура без обвинений
Главное — не искать виноватого, а исправить процесс:
# НЕПРАВИЛЬНЫЙ разговор:
# "Ты допустил баг в production!"
# ПРАВИЛЬНЫЙ разговор:
# "В production попала ошибка. Давайте посмотрим:
# - Почему code review не поймал это?
# - Почему тесты не поймали это?
# - Как улучшить процесс?"
8. Логирование ошибок
import logging
from functools import wraps
logger = logging.getLogger(__name__)
def log_errors(func):
"""Decorator для логирования ошибок."""
@wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
logger.error(
f"Error in {func.__name__}",
exc_info=True, # Логирует полный traceback
extra={
"function": func.__name__,
"args": str(args)[:100], # Безопасность
"kwargs": str(kwargs)[:100],
}
)
raise
return wrapper
@log_errors
def critical_operation():
# Любая ошибка здесь будет залогирована
pass
9. Вычленение и изоляция ошибок
# Избегаем каскадных ошибок
def process_payment(order_id):
try:
order = get_order(order_id) # Может упасть
except OrderNotFound:
logger.warning(f"Order not found: {order_id}")
return None # Не падаем, возвращаем None
try:
receipt = process_with_payment_gateway(order) # Может упасть
except PaymentGatewayError as e:
logger.error(f"Payment gateway error for order {order_id}", exc_info=True)
# Не падаем, уведомляем support
notify_support(f"Payment failed for order {order_id}")
return None
return receipt
Мой набор инструментов
# 1. Type hints — предотвращают типизные ошибки
def greet(name: str) -> str:
return f"Hello, {name}"
# 2. Assertions для проверок
assert isinstance(user, User), "User must be User instance"
# 3. Контекстные менеджеры для cleanup
with database.transaction():
# Если что-то сломается, откатываем
process_data()
# 4. Sentry для production мониторинга
import sentry_sdk
sentry_sdk.init("https://...")
# 5. Структурированное логирование
logger.info("Payment processed", extra={
"order_id": order_id,
"amount": amount,
"status": "success"
})
Философия
Ошибки неизбежны. Но:
✅ Я пишу код, ожидая что что-то может сломаться ✅ Я тестирую edge cases и failure scenarios ✅ Я логирую для debug и мониторинга ✅ Я обрабатываю ошибки граммотно (не молчу) ✅ Я анализирую production ошибки и улучшаю процесс ✅ Я не обвиняю разработчиков, я улучшаю инструменты ✅ Я разделяю ошибки на уровни (warning vs error) ✅ Я имею recovery механизмы (retry, fallback)
Итог: Ошибки — это не трагедия, это сигнал что нужно улучшить либо код, либо тесты, либо процесс. Главное — не повторять одну и ту же ошибку дважды.