Расскажи про свой опыт выявления нефункциональных требований
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Опыт выявления нефункциональных требований
Что такое нефункциональные требования
Прежде всего, различие между функциональными и нефункциональными требованиями:
Функциональные требования:
- Описывают ЧТО должна делать система
- Пример: "Система должна позволять пользователю искать объявления по цене и местоположению"
- Это видимо пользователю
Нефункциональные требования (NFR - Non-Functional Requirements):
- Описывают КАК система должна это делать
- Могут быть невидимы конечному пользователю, но влияют на качество
- Области: производительность, безопасность, масштабируемость, надёжность, удобство использования
История из моей практики: проект интеграции платёжной системы
Начало проекта (ошибка)
Получил требования от Product Manager:
Требование: "Система должна обрабатывать платежи"
Это ТОЛЬКО функциональное требование.
Я начал писать требования для разработчиков, но не подумал о NFR.
Во время разработки произошло следующее:
-
Разработчик реализовал синхронный платёж
def process_payment(user_id, amount): payment_result = payment_api.charge(user_id, amount) if payment_result.success: save_to_db(user_id, amount, "completed") return payment_result -
На production случился сценарий:
- Платёж успешно обработан (деньги взяли)
- Но сохранение в БД занимает 5 секунд
- Пользователь видит таймаут
- Пользователь думает, что платёж не прошёл, и нажимает "Повторить"
- Система обрабатывает второй платёж
- Деньги взяли дважды, но записано только два раза
- Наступил кошмар с возвратом денег
Выявление нефункциональных требований
После инцидента я провел анализ и выявил недостающие NFR:
NFR #1: Idempotency (идемпотентность)
Требование, которое я упустил:
Требование:
- Система должна гарантировать, что один платёж не будет обработан дважды
- Даже если пользователь отправит запрос несколько раз
- Метрика успеха: 100% гарантия идемпотентности
Решение:
- Генерируем уникальный idempotency_key для каждого платежа
- Проверяем в БД: был ли уже платёж с таким ключом?
- Если да, возвращаем существующий результат
def process_payment(user_id, amount, idempotency_key):
# Проверяем, был ли уже обработан платёж
existing_payment = Payment.query.filter(
Payment.idempotency_key == idempotency_key
).first()
if existing_payment:
return existing_payment # Возвращаем старый результат
# Новый платёж
payment_result = payment_api.charge(user_id, amount)
payment = Payment(
user_id=user_id,
amount=amount,
idempotency_key=idempotency_key,
status=payment_result.status
)
db.session.add(payment)
db.session.commit()
return payment
NFR #2: Timeout Handling (обработка таймаутов)
Требование:
- Если платёж обрабатывается более 10 секунд, система должна вернуть таймаут
- Но не отменять платёж
- Асинхронно проверить статус платежа и завершить
- Метрика: 99.99% платежей в итоге либо успешны, либо отменены (не зависшие)
Решение:
- Используем асинхронную очередь (Celery, RabbitMQ)
- Синхронно отправляем запрос платежной системе с таймаутом 10 сек
- Если таймаут, отправляем job в очередь для проверки статуса
- Job периодически проверяет реальный статус платежа
NFR #3: Error Recovery (восстановление после ошибок)
Требование:
- При сбое платёжной системы
- Система должна повторить попытку не менее 3 раз
- С экспоненциальной задержкой (1 сек, 2 сек, 4 сек)
- Метрика: 99.5% успешных платежей (даже при перебоях)
Решение:
- Добавляем retry logic с exponential backoff
- Каждый retry логируем и отслеживаем
NFR #4: Security (безопасность)
Требование:
- Платёжные данные не должны сохраняться в нашей БД
- Использовать tokenization от платёжной системы
- Все запросы к API платежей должны идти через HTTPS
- Логировать все попытки платежей (для аудита)
- Метрика: 0 утечек платёжных данных, 100% логирование
Решение:
- Интегрируем Stripe / Yandex.Kassa с их security стандартами
- Сохраняем только token платежа, не полные данные карты
- Используем PCI DSS compliant API
NFR #5: Performance (производительность)
Требование:
- 95% платежей должны обработаться за ≤ 2 сек
- Система должна выдерживать 1000 одновременных платежей
- При нагрузке 1000 платежей/сек
- Метрика: P95 latency < 2000ms, 99% success rate
Решение:
- Используем async/await для параллельной обработки
- Кешируем информацию о валютах и курсах
- Используем connection pooling к БД
- Тестируем load testing'ом
NFR #6: Auditability (аудитность)
Требование:
- Каждый платёж должен быть отслежен
- Финансовый отдел должен видеть историю
- Налоговая служба должна видеть полный аудит
- Метрика: 100% платежей имеют полный audit trail
Решение:
- Создаём таблицу payment_audit_log
- Логируем КАЖДОЕ действие
- Immutable records (нельзя удалить)
- Криптографическая подпись для целостности
Методология: как я выявляю нефункциональные требования
Техника 1: Вопросы для каждого компонента
Для компонента "Обработка платежей" я задаю вопросы:
1. Производительность:
✓ Сколько времени должен занимать платёж?
✓ Сколько одновременных платежей должна выдержать система?
✓ Какой максимальный объём платежей в сутки?
2. Надёжность:
✓ Что если платёжная система недоступна?
✓ Что если произойдёт сбой в середине обработки?
✓ Как восстановиться после сбоя?
✓ Гарантируется ли 100% обработка всех платежей?
3. Безопасность:
✓ Где хранятся платёжные данные?
✓ Кто имеет доступ к платёжным данным?
✓ Как защищены данные в пути?
✓ Какие компиентированы стандарты (PCI DSS)?
4. Масштабируемость:
✓ Может ли система обработать 10x нагрузку?
✓ Как добавить новую платёжную систему без перестройки?
✓ Сможет ли она расти с бизнесом?
5. Удобство:
✓ Какой должна быть ошибка платежа для пользователя?
✓ Сколько времени ждёт пользователь?
✓ Может ли пользователь видеть историю платежей?
Техника 2: Analyse Quality Attributes
Использую FURPS+ модель:
F - Functionality (функциональность) ✗ это было, я добавляю остальное
U - Usability (удобство использования)
✓ Платёж должен казаться пользователю быстрым
✓ Ошибки должны быть понятны
✓ История платежей должна быть видна
R - Reliability (надёжность)
✓ 99.95% успешных платежей
✓ Нулевая вероятность двойных платежей
✓ Восстановление после сбоев
P - Performance (производительность)
✓ < 2 сек на обработку платежа
✓ 1000 платежей одновременно
✓ 99% в пиковые часы
S - Supportability (поддерживаемость)
✓ Логирование всех операций
✓ Мониторинг платежей в real-time
✓ Алерты при проблемах
+ Design Constraints
✓ Используем PostgreSQL
✓ Интегрируемся с Stripe
✓ Deploy на AWS
Техника 3: Проектные сценарии (Use Case Analysis)
Для каждого use case я спрашиваю:
Use Case: "Оплата заказа"
1. Happy Path (всё хорошо):
✓ Платёж успешен (Requirement: < 2 sec)
2. Retry (ошибка сети)
✓ Первая попытка не удалась
✓ Системе нужно повторить
(Requirement: retry up to 3 times)
3. Timeout (долгая обработка)
✓ Платёж обрабатывается > 10 сек
✓ Пользователь не ждёт
(Requirement: async processing)
4. Duplicate (пользователь дважды нажал)
✓ Платёж отправлен дважды
(Requirement: idempotency)
5. Fraud (подозрительный платёж)
✓ Система должна заблокировать
(Requirement: fraud detection)
6. Refund (возврат)
✓ Пользователь просит вернуть деньги
(Requirement: refund within 24 hours)
Примеры нефункциональных требований из разных областей
Для Search System (поисковая система)
NFR #1: Response time
- P95 < 500ms для запросов
NFR #2: Scalability
- Должна обработать 10,000 запросов в секунду
NFR #3: Index freshness
- Новый документ видно в поиске за 30 секунд
NFR #4: Uptime
- 99.95% availability
Для Data Pipeline (обработка данных)
NFR #1: Data consistency
- Данные не должны дублироваться
- Все события должны быть обработаны один раз
NFR #2: Latency
- Данные должны попасть в хранилище за 5 минут
NFR #3: Fault tolerance
- При сбое одного ноды, pipeline продолжает работать
NFR #4: Observability
- Видно в real-time, сколько данных обработано
Как я документирую нефункциональные требования
Темплейт требования:
ID: NFR-001
Название: Идемпотентность платежей
Описание: Система должна гарантировать, что один платёж не будет обработан дважды
Критерии приёма:
- Каждый платёж имеет уникальный idempotency_key
- При повторном запросе с тем же ключом возвращается старый результат
- Протестировано на 10,000 дублированных платежей
- 100% успешных случаев
Приоритет: CRITICAL (финансовые потери)
Этап реализации: Backend API
Ошибки, которые я допускал
1. Забыл про error handling
- Функция работает, но что если ошибка?
- Теперь всегда спрашиваю: "А что если это сломается?"
2. Не спросил про максимальную нагрузку
- Система работала на 100 пользователей
- Но когда пришло 10,000 - упала
- Теперь в требованиях всегда указываю capacity
3. Забыл про логирование
- На production ошибка, но что случилось - непонятно
- Теперь требую полный audit trail
4. Не подумал про восстановление
- Система была сломана 2 часа
- Восстанавливали вручную
- Теперь требую автоматическое восстановление
5. Не спросил про удобство
- Система работает, но UI ужасный
- Теперь включаю NFR по usability
Практический совет
Расскажу про метод ATAM (Architecture Tradeoff Analysis Method):
Когда выявляю NFR, спрашиваю:
-
Какие ограничения у нас есть?
- Бюджет: $100K на разработку
- Время: 6 месяцев
- Team: 5 разработчиков
-
Какие NFR наиболее важны?
- Security: критично (деньги пользователей)
- Performance: очень важно (UX)
- Scalability: важно (рост бизнеса)
- Cost: важно (бюджет)
-
Какие trade-offs?
- Высокая производительность требует дорогой инфраструктуры
- Высокая надёжность требует времени на разработку
- Быстрая разработка требует меньше качества
-
Что выбираем?
- Security > Performance > Scalability
- Готовы потратить время на security
- Производительность улучшим потом
Это помогает понять приоритеты и избежать избыточных требований.