Продукт і вимоги

Уточнення вимог: як прояснити невизначеність до коду

Глави 07–08 допомогли знайти потребу й описати потрібну поведінку. Тепер перед кодом з’ясуйте, які твердження допускають несумісні тлумачення, що можна…

Глава 9Заморожене українське видання

Після цієї глави

Глави 7–8 допомогли знайти потребу й описати потрібну поведінку. Тепер перед кодом з’ясуйте, які твердження допускають несумісні тлумачення, що можна встановити з джерел, а яке рішення має прийняти власник продукту.

Специфікація записує очікувану поведінку й умови її роботи. Уточнення прибирає конкретну невідомість: знайти джерело, дослідити код чи документацію або запитати людину, уповноважену прийняти рішення. Мета — не вгадувати й не перетворювати кожну задачу на довгу анкету, а з’ясувати те, що може змінити поведінку, доступ, обсяг чи ризик.

Шість типів тверджень

У главі 8 позначки показують, на чому ґрунтується твердження: на спостереженні, свідченні, висновку, припущенні чи рішенні. Тут ми дивимося на нього з іншого боку: що саме треба підтвердити або вирішити. У тексті задачі ці види часто змішані.

Тип Приклад Що робити
Потреба «Покупці не знають, чи встигнуть скасувати замовлення» Звірити зі зверненнями або дослідженням, не узагальнювати один випадок на всіх.
Правило поведінки «Замовлення можна скасувати до початку комплектування» Перевірити межі, винятки, ролі й чинну політику.
Факт про систему «Після скасування платіжний сервіс повертає кошти» Перевірити код, налаштування, договір або інше надійне джерело.
Припущення «Мабуть, менеджер може скасувати будь-яке замовлення» Позначити невідоме й не перетворювати його на вимогу.
Продуктове рішення «Дозволити скасування після початку комплектування?» Звернутися до власника рішення, якщо джерела не дають відповіді.
Спосіб реалізації «Зберігати прапорець cancelled» Не плутати технічну пропозицію з потрібною поведінкою; спершу з’ясувати, що має відбутися.

Це різні класифікації: позначка з глави 8 описує підставу твердження, а ця таблиця — його зміст. Важливі джерела, відповідальних і невирішені питання зберігайте у короткому записі наприкінці глави.

Для критичного твердження також зазначте рівень упевненості й точне джерело: «знайшли в чинній політиці» відрізняється від «це попереднє припущення» або «так відповіла керівниця продукту». Якщо джерела немає, запишіть це прямо. Так команда не сприйматиме чинний код як доказ того, що саме таку поведінку дозволено.

Звідки береться невизначеність

Джерела неоднозначності у вимогах

Пропуск. «Користувач може повернути оплату» не визначає, хто саме, яку оплату й коли. Спершу перевірте умови, код і попередні рішення; якщо відповіді немає, запитайте про наслідок, який змінює роботу.

Двозначне слово або термін. «Швидко», «активний», «новий», «підтримувати», «видимий» і «синхронізувати» можуть означати різне. Якщо інше тлумачення змінить реалізацію, знайдіть визначення або погодьте спостережувану межу. Наприклад, «оновлення з’являється за десять секунд» чіткіше за «миттєво», але таку межу не слід вигадувати без власника й доказу потреби.

Термін без визначення заслуговує окремої перевірки. «Робочий день» може означати календарний день, день у часовому поясі клієнта або банківський операційний день. Знайдіть визначення в чинній політиці чи попросіть його у відповідального власника, а тоді використовуйте одне значення у вимозі й перевірках.

Суперечність. Задача дозволяє всім співробітникам бачити контакт, а політика приватності — лише призначеному фахівцеві. Перевірте дати, власників і те, чи йдеться про ті самі дані; з’ясуйте пріоритет джерел і зафіксуйте розв’язання конфлікту. Не вибирайте мовчки зручніше правило.

Час або стан без межі. «Змінити того ж дня» не визначає часову зону чи поведінку рівно на межі; «замовлення активне» не каже, що змінить доставку або блокування. Назвіть початок, кінець і подію, яка переводить систему в інший стан.

Немає власника рішення. Учасник може пояснити чинний код, але не мати права визначати нову політику повернення. Знайдіть відповідальність у командній домовленості, Jira чи системі ролей і зверніться до уповноваженої людини. Якщо власника не визначено, це окреме питання керування, а не дозвіл розробнику вирішити навмання.

Від звичайного сценарію до важливих винятків

Основний сценарій і крайові випадки

Основний сценарій показує звичайний шлях до результату: покупець відкриває власне замовлення й скасовує його до початку комплектування. Але він нічого не каже про некоректні, повторні, запізнілі чи одночасні дії.

Для вимоги, яка змінює поведінку, подумайте про чотири групи ситуацій:

  • Вхід і дані: поле порожнє, формат неправильний, значення відсутнє або завелике.
  • Межа: дія стається за секунду до строку, рівно на межі чи одразу після неї.
  • Повтор і час: кнопку натиснули двічі, запит повторився після затримки, сторінка застаріла або запити прийшли не в тому порядку.
  • Стан і доступ: замовлення вже відправлено, доступ відкликали або користувач більше не має потрібної ролі.

Це перелік для роздумів, а не вимога додавати кожен варіант у продукт. Залишайте випадки, де різне тлумачення має помітний наслідок; відкидайте теоретичну екзотику, що не змінює поведінки чи ризику.

Для кожного важливого сценарію назвіть спостережуваний результат: що побачить користувач, що зміниться в даних і чи безпечно повторити дію. «Обробити помилку» — не результат. А от показати статус скасування, не створити друге повернення й запропонувати зв’язатися з підтримкою — уже поведінка, яку можна погодити.

Межа й повторна дія

Вимога каже: «Скасування доступне до початку консультації». Консультацію призначено на 15:00 за Осло. Сторінка показує кнопку о 14:59, а сервер отримує запит рівно о 15:00. Чи проходить дія? Якщо запис перенесли, який час визначає межу — початковий чи новий? Якщо кнопку натиснули двічі, чи може платіжна система повернути гроші двічі?

Спершу перевірте, чи визначено часову зону й момент переходу в стан «почалася», а також чи безпечно платіжна система обробляє повтор. Якщо відповідь є у політиці або документованому API, знайдіть її там. Якщо правила немає, поставте власнику одне запитання, яке охоплює межу, перенесення й повтор: відповідь змінює програмну поведінку та фінансове очікування.

Як вибрати, що питати першим

Як визначити пріоритет запитань для уточнення

Оцініть невідомість за наслідком помилки, імовірністю помилки, ціною повернення назад і тим, чи блокує вона наступну роботу. Це корисна евристика, не стандартна формула.

Пріоритет Сигнал Приклад
Високий Помилка зачіпає гроші, персональні дані, права, незворотну дію або значну переробку Чи повертати гроші після відправлення замовлення?
Середній Вибір змінює один сценарій, але його можна ізолювати й безпечно відкласти Чи показувати номер відправлення поруч із датою доставки?
Низький Різниця косметична, оборотна й не блокує важливий сценарій Який із двох рівнозначних написів на кнопці використати?

Почніть із невідомого, яке може заблокувати або зробити хибною наступну роботу. Відкладіть необоротне рішення лише тоді, коли погоджено тимчасову поведінку, яку не сплутають з остаточним правилом. Не ховайте доступ чи приватність у «припущеннях до уточнення».

Хороше запитання називає конкретне правило, пропонує зрозумілі варіанти, коротко показує наслідки та позначає рекомендацію команди. Варіанти не мають підштовхувати до відповіді, зручної автору. Якщо існує безпечний стандарт, назвіть його, але не маскуйте відсутність політики словом «за замовчуванням».

Невдале: «Що робити зі скасуванням? Уточніть усі вимоги».

Краще: «Чинна політика не визначає, чи можна скасувати замовлення після початку комплектування. Варіант A — прибрати самостійне скасування й запропонувати звернутися до підтримки. Варіант B — дозволити скасування, але не повертати кошти автоматично. Це змінює стан замовлення й оплату. Я рекомендую не запускати повернення без окремого правила. Хто має його затвердити?»

Якщо потрібні відповіді на кілька пов’язаних пунктів, згрупуйте їх у короткий пакет. Не надсилайте десяток дрібних запитань про підписи й відступи, поки неясно, кому взагалі дозволена дія.

Ризик визначає, кого і про що питати

Чотири ризики з глави 7 підказують, який доказ і в кого шукати (Marty Cagan, The Four Big Risks):

  • Цінність: чи справді це розв’язує для людей значущу проблему? Потрібні свідчення й поведінка користувачів, не лише припущення команди.
  • Зручність: чи може людина зрозуміти й виконати потрібну дію? Спостерігайте за сценарієм; Steve Krug нагадує прибирати невизначеність у назвах і наступних кроках (Don’t Make Me Think).
  • Здійсненність: чи може команда реалізувати й підтримувати рішення за наявних систем, даних і обмежень? Це питання для інженерної перевірки.
  • Життєздатність: чи сумісне рішення з бізнесом, операціями, юридичними зобов’язаннями й відповідальністю? Це вирішують уповноважені власники, а не той, хто швидше відповів у чаті.

Не зводьте невідоме до питання «чи можемо це закодувати?».

Фахівець може перевірити систему, але не визначити замість власника, яка поведінка дозволена. А якщо невідомо, яке повідомлення побачить людина, це теж вимога, яку треба з’ясувати до дизайну й реалізації; про зрозумілу взаємодію йдеться в главі 8.

Обмеження замість безмежного уточнення

Як і в pitch із Shape Up, зафіксуйте проблему, часову межу роботи (appetite), підхід, ризикові невідомі (rabbit holes) та те, що не входить у зміну (no-gos); детальніше підхід описано в главі 8 (Shape Up, Shape the work). Уточнюйте невідомі, що загрожують погодженому обсягу, а не весь майбутній продукт. Короткий запит не має непомітно перетворюватися на специфікацію всього продукту.

Уточнення має робочий критерій завершення: рішення записано, власник відомий, ключовий сценарій можна описати, ризикові межі зрозумілі. Те, що можна безпечно відкласти, переходить у список припущень або майбутню задачу з власником і датою перегляду. Тихо розширювати цілі чи додавати непідтверджені вимоги не можна.

Як агент уточнює запит: спершу пошук, потім питання

Коли агент отримує задачу, спершу нехай шукає відповідь у доступному контексті, а не питає про те, що вже є в задачі чи репозиторії.

  1. Прочитати задачу, критерії приймання, коментарі, посилання й рішення, на які вона спирається.
  2. Знайти відповідні документи, код, конфігурацію та перевірки; код показує поточну поведінку, але не обов’язково дозволену.
  3. Звірити технічні факти з офіційною документацією. Записати джерело, власника рішення, припущення й те, що лишилося невідомим.
  4. Запитати лише про невирішене, що вплине на поведінку, ризик чи обсяг. Після відповіді оновити вимогу й позначити суперечливий старий запис як замінений.

Якщо назва стану не визначена, агент спершу шукає її в моделі даних і пов’язаному API, а не питає про те, що можна встановити читанням коду. Але код може описувати чинну поведінку, не бажану. Коли він суперечить політиці чи новій задачі, зафіксуйте конфлікт і знайдіть власника рішення.

Режими планування в Codex і Claude Code допомагають спершу дослідити задачу й узгодити кроки (Codex Plan, Claude Code Plan mode). Але поведінка залежить від версії, інтерфейсу й дозволів: у терміналі Claude Code, де доступний bypassPermissions, цей режим може зняти блок запису під час планування. Не вважайте назву режиму гарантією; перевірте актуальні правила свого середовища.

Як записати припущення

Якщо можна безпечно продовжити, явно запишіть тимчасове припущення, його власника, строк перегляду й те, що доведеться змінити за іншого рішення. Не припускайте поведінку, яка впливає на доступ, приватність, гроші чи незворотні дії: спершу потрібне рішення власника.

«Можу скасувати» не означає «можу повернути гроші». «Номер телефону прихований у списку» не означає, що його неможливо отримати через API. Вимога називає кожний потрібний результат і роль, а не покладається на здогад агента.

Повні розбори

Приклад 1. «Покупець може скасувати замовлення»

Початковий запит. «Додати можливість скасування замовлення». Це напрям роботи, але ще не правило.

Послідовність пошуку джерел. Агент спершу читає задачу, її критерії, коментарі та пов’язані рішення. Далі перевіряє сторінку замовлення й чинні умови скасування з датою та власником, матрицю ролей, поточний маршрут запиту в коді й тести, а також документацію платіжного сервісу про статус повернення та безпечну перевірку після тайм-ауту. У короткому записі він для кожного джерела фіксує, що саме воно доводить і коли його перевірено. Код може показати, що саме система робить зараз, але сам по собі не встановлює, що дозволяє політика.

Що агент знаходить. Чинна політика дозволяє покупцеві скасувати замовлення до 15:00 за часовою зоною складу в день перед відправленням; після цього покупець звертається до підтримки. Поточний код показує ролі й обробку запиту, а документація платіжного сервісу — як перевірити статус повернення. Ці джерела не визначають, чи включна межа о 15:00, від якої дати рахувати строк після перенесення відправлення та що робити, якщо відповідь про повернення загубилася. Не слід виводити нове правило з того, що вже випадково дозволяє інтерфейс.

Що уточнити. Це впливає на доступ до скасування й гроші, тому агент питає власника замовлень і фінансів: «Якщо дату відправлення змінили, застосовувати строк до нової підтвердженої дати? Запит, що надійшов серверу рівно о 15:00, ще приймаємо чи вже передаємо підтримці? Якщо платіжний сервіс не відповів, перед повтором перевіряємо статус, щоб не створити друге повернення? Чи може підтримка змінити статус без автоматичного повернення?» Питання називають варіанти й наслідки, а не просять замовника повторно описати всю функцію.

Рішення й вимога. Власник підтверджує, що строк рахується від нової підтвердженої дати за часом складу; запит, отриманий сервером рівно о 15:00 чи раніше, приймається, пізніший переходить до підтримки; повтор не створює другого повернення. Після межі підтримка може позначити замовлення скасованим, але повернення відбувається лише за окремим підтвердженим правилом. Покупець бачить самостійне скасування лише до межі; після неї — зрозумілий шлях до підтримки. Якщо платіжний сервіс не повідомив результат, система спершу звіряє статус замовлення й повернення, а тоді пропонує безпечну наступну дію.

Контракт станів і перевірка. Порожній список не показує кнопку скасування. Поки запит триває, картка лишається видимою, показано перебіг дії, повторне натискання заблоковано. Після успіху статус стає «Скасовано», а підтвердження не обіцяє повернення без окремого підтвердження. Після помилки запис не зникає: повідомлення пояснює, що сталося, і пропонує підтримку або безпечний повтор; якщо відповідь сервера загубилася, спершу оновлюється статус. Перевірте покупця й роль підтримки, запит за секунду до межі, рівно о 15:00 та після неї, нову дату відправлення, тайм-аут після прийнятого запиту й повтор із перевіркою статусу. Зіставте UI, API, журнал операції та платіжний статус; переконайтеся, що скасування не створює другого повернення.

Приклад 2. Документи суперечать про видимість контакту

Початковий запит. «Показати номер телефону в картці клієнта». Чинність незрозуміла: документ філії обмежує доступ призначеним фахівцем, старий опис експорту дозволяє його всім, а API повертає повний номер попри маскування в інтерфейсі.

Послідовність перевірки. Агент фіксує дату й власника кожного документа, відкриває чинну матрицю ролей, конфігурацію експорту, історію рішень, тести доступу та реальну API-відповідь. Він розділяє два твердження: «інтерфейс маскує номер» описує поточну видимість на екрані, а «роль має право бачити номер» — політику. Код доводить перше, але не друге. Поки власниця даних не підтвердила пріоритет, конфлікт залишається відкритим і повний номер не можна вважати дозволеним лише тому, що API його повертає.

Запис рішення. Власниця даних підтверджує, що правило філії чинне, а документ експорту застарів. Записуємо власницю й дату рішення, посилання на чинне правило, документ, який воно замінює, обсяг застосування та потребу оновити експортну інструкцію. Це не просто відповідь у чаті: команда має знати, який текст тепер є джерелом істини.

Власниця уточнює: повний номер бачать призначений фахівець і спеціально дозволений менеджер; відсутність призначення не надає доступу; для інших ролей номер маскується й не передається через API або експорт. Перевірте це для кожної ролі: маска на екрані не захищає дані, якщо API або CSV усе ще містить повний номер.

Роль або стан Картка API Експорт
Призначений фахівець Повний номер Повний номер для цього клієнта Повний номер лише в дозволеному обсязі
Дозволений менеджер Повний номер Повний номер за наданим дозволом Повний номер лише в дозволеному обсязі
Інший співробітник Масковане поле Повне значення не передається Повне значення не експортується
Немає призначеного фахівця Доступ не надається автоматично Відмова або відсутність поля без витоку Не включати повне значення

Перевірка. Увійдіть тестовими обліковими записами кожної ролі; повторіть прямий API-запит з ID дозволеного та чужого клієнта; перевірте експорт, відсутнє призначення, зміну ролі й відкликання дозволу. Зіставте відповідь, фактичний файл експорту та журнал, переконайтеся, що повний номер не потрапляє в повідомлення про помилку чи звичайний лог. Власниця підтверджує політику, а інженерна перевірка — що обмеження справді діє в усіх шляхах.

Приклад 3. «Покращити авторизацію»

Невдале перше питання агента. «Який колір кнопки входу ви хочете?» Запит «покращити авторизацію» спершу потребує перевірки доступу й поведінки входу.

Що він перевіряє. Агент читає попередню задачу про повторні входи, правила ролей, чинну політику сесій, відомі дефекти й тести. Припустімо, документи вимагають не відкривати захищені дані після невдалої автентифікації, але не визначають, чи блокувати акаунт після серії спроб. Логи показують повторні входи, однак самі по собі не доводять, що це атака або що акаунт треба блокувати.

Питання у порядку наслідків.

  1. «Після кількох хибних паролів блокувати акаунт, сповільнити спроби чи не змінювати поведінку? Блокування може відрізати власника акаунта; логи не визначають продуктового правила. Потрібне рішення власника безпеки чи продукту».
  2. «Чи змінюється правило для адміністратора й звичайного користувача?» Поточна політика каже, що правило однакове; агент перевіряє джерело, перш ніж ставити це питання як невідоме.
  3. «Який відтінок кнопки використати?» Це оборотна косметична деталь, тож її можна відкласти.

Рішення й межа прикладу. У вигаданому прикладі власник вирішує не блокувати акаунт, а після п’яти помилок за 15 хвилин затримувати наступну спробу на дві хвилини; нейтральне повідомлення не розкриває існування акаунта. Це демонстраційна політика, не рекомендація з кібербезпеки.

Критерій приймання. Для одного акаунта сервер рахує хибні спроби у ковзному 15-хвилинному вікні. Після п’ятої хибної спроби наступна приймається не раніше ніж за дві хвилини. Відповідь не розкриває, чи існує введений акаунт. Після успішного входу лічильник очищається. Користувач бачить нейтральне повідомлення про затримку; акаунт не блокується.

Перевірка й межі. Перевірте п’яту та шосту невдалі спроби, межу вікна, повтор після затримки, правильний пароль після затримки, вихід першої помилки з вікна, невідомий акаунт, різні ролі та паралельні запити. Ще треба з’ясувати, де зберігається лічильник і чи не суперечить правило чинним нормам безпеки. Детальний критерій не доводить, що продуктове рішення правильне: політику затверджує власник, здійсненність — інженер. Критерії приймання й докази докладніше розглянуто в главі 10.

Реальна GitHub-дискусія: неоднозначність вимоги й перевірюване переформулювання

Робочі матеріали ASVS v5 — Application Security Verification Standard, стандарту перевірки безпеки застосунків OWASP — показують, як уточнюють неоднозначну вимогу. Issue #1744, відкритий 4 жовтня 2023 року, питає, чи покриває тодішня вимога 5.1.4 про схеми й дозволені символи вільний текст, наприклад повідомлення чату, із символом Right-To-Left Override (RTLO, U+202E), який може візуально приховати розширення файла (issue #1744, коментар про межу перевірки).

Пов’язаний issue #1640 «5.2.2 sounds like input validation» стосується розмитої вимоги про санітизацію. 12 серпня 2024 року запропонували об’єднати її з 5.1.3 як дубль; коментар у #1744 послався саме на цю ранню пропозицію як на можливе покриття RTLO. Після заперечень від цього варіанта відмовилися. Пізніша пропозиція залишила 5.2.2 окремою й уточнила правило: обробляти дані перед передаванням у потенційно небезпечний контекст, дозволяти безпечні для нього символи й обрізати надто довгий ввід (#1744, #1640, рання пропозиція, посилання з #1744, уточнена пропозиція).

Уточнену редакцію внесли в PR #2028, пов’язаний з #1640 і злитий 26 серпня 2024 року; його diff безпосередньо підтверджує зміну формулювання. Issue #1744 закрили 3 вересня коротким коментарем «I think that is covered» (коментар про закриття), але в ньому не названо PR #2028. Тому зв’язок між закриттям issue й цією зміною — висновок за хронологією, а не прямо підтверджений факт. Обговорення й diff доводять редакторське уточнення, але не зміну коду чи виміряний ефект безпеки.

Номери вимог залежать від версії: у стабільній ASVS 5.0.0 відповідна вимога має номер 1.3.3 (рекомендація вказувати версію, ASVS 5.0.0).

Короткий запис вимоги й рішення

Для важливого рішення вистачить короткого запису:

  • Правило: одна поведінкова вимога з умовою та видимим результатом.
  • Джерело: URL, задача, власник рішення або точний шлях у коді; додайте дату перевірки.
  • Статус: факт, продуктове рішення, припущення або відкрите питання.
  • Власник: хто вирішує невідоме й хто перегляне припущення.
  • Наслідок: які користувачі, ролі, дані, межі, інтеграції чи перевірки зміняться.
  • Наступний крок: пошук джерела, запитання, оновлення документа або умова безпечного продовження.

Якщо нова відповідь суперечить старому тексту, позначте його як замінений і дайте посилання на рішення; збережіть дату, автора й причину. Не залишайте два чинні документи з різними правилами. Повну структуру PRD розглянуто в главі 8, а зв’язок вимог із доказами перевірки — у главі 10.

Джерела та подальше читання

Після цієї глави читач може перевірити, чи відповідь уже є в доступному джерелі; назвати невідоме без домислу; поставити власнику конкретне питання з наслідками варіантів; оформити відповідь як вимогу з джерелом і перевірними прикладами; або безпечно відкласти обмежене припущення з власником і датою перегляду. У главі 10 перетворимо погоджену вимогу на критерії приймання й докази перевірки.