← Назад к вопросам

Как относишься к ошибкам?

1.0 Junior🔥 101 комментариев
#Soft Skills

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как относишься к ошибкам?

Этот вопрос о профессиональной зрелости разработчика. Я расскажу о правильном отношении к ошибкам в контексте профессиональной разработки.

Мой подход к ошибкам

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)

Итог: Ошибки — это не трагедия, это сигнал что нужно улучшить либо код, либо тесты, либо процесс. Главное — не повторять одну и ту же ошибку дважды.

Как относишься к ошибкам? | PrepBro