Організація виконання

Реалізація вертикального зрізу: від наміру до прийнятого результату

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

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

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

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

Передумови. Глави 7–44 дали складники цього процесу: визначення проблеми, контекст і джерела правди, технічний дизайн, критерії, агентські цикли, роботу з гілками, огляд змін та оркестрацію. Глава 19 уже показала вертикальні зрізи на прикладах перегляду й скасування бронювання. Наступна глава, 46, докладніше розбирає контракт завдання для агента; тут він потрібен лише як стислий робочий бриф.

Усі назви людей, систем і показники в навчальних кейсах нижче вигадані. Це не звіт про виконаний код чи виробничу систему. Реальний публічний приклад Django позначений окремо та описаний лише в межах перевірених фактів.

45.1. Від користувацького наміру до рішення про роботу

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

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

Це розрізнення узгоджується з рамкою ризиків продукту Марті Кагана: цінність для клієнта, зручність, здійсненність і життєздатність для бізнесу — окремі ризики (The Four Big Risks). Код і автоматизовані перевірки дають свідчення переважно про здійсненність; вони самі не перевіряють попит або бізнесову економіку. У статті про відкриття продукту Каган описує дослідження проблеми й перевірку припущень із користувачами, не вимагаючи від кожної команди однакового порядку дій (Product Discovery, авторська стаття; повну книгу Inspired тут не приписуємо собі як прочитану).

До початку реалізації зберіть посилання на авторитетні артефакти й коротко зазначте, що з них випливає:

Артефакт Що автор має встановити
Запит або опис проблеми Хто стикається з проблемою і яка поведінка має змінитися
Уточнення та рішення власника продукту Політика строку перенесення, тип запису, межі доступу й невирішені питання
Критерії приймання Спостережуваний результат для успіху, відмови та відновлення
Чинні архітектурні рішення Яке сховище, програмний інтерфейс застосунку (API, application programming interface), авторизація й компоненти вже є джерелами істини
Схема даних і контракт API Які ідентифікатори й часові поля авторитетні; що очікують клієнт і сервер
Пов’язані задачі та попередня реалізація Що вже завершено і куди не слід дублювати історію

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

45.2. Межа зрізу: достатньо мало, але все ще правильно

Для першого варіанта встановімо ціль: клієнт переносить один майбутній підтверджений запис на інший вільний час. Мінімальний зріз проходить через дані, серверну логіку, API та інтерфейс користувача (UI, user interface), якщо саме ці компоненти потрібні в чинній архітектурі.

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

За межами: створення нового бронювання, зміна оплати, синхронізація календаря, автоматичне повідомлення третім сторонам, адміністративний редактор і перебудова всієї системи записів. Якщо вимогу про сповіщення схвалять пізніше, це буде окрема пов’язана робота. Зменшення обсягу може відкласти анімацію чи додатковий канал повідомлень, але не може прибрати перевірку власника, збереження узгодженого стану чи повідомлення про помилку. У підході Shape Up «час обмежений, обсяг змінний» — це спосіб домовитися про межі ставки, а не дозвіл зробити неповною критично важливу властивість (Shape Up: Set Boundaries). У главі про завершення одного елемента Райан Сінгер описує ранню інтеграцію інтерфейсу й серверної частини як спосіб отримати перевірювану робочу поведінку; це метод із конкретної практики Basecamp, а не універсальне правило розміру запиту на злиття (PR, pull request) (Shape Up: Get One Piece Done, джерела перевірено 24 вересня 2026 року).

Уявний контракт сценарію можна записати так:

  1. Авторизований клієнт відкриває власне майбутнє підтверджене бронювання.
  2. Сервіс показує доступні для цього ресурсу й періоду часу варіанти.
  3. Клієнт обирає один варіант і надсилає його для свого бронювання.
  4. Сервер ще раз перевіряє право, чинний статус і наявність варіанта, а потім зберігає перенесення узгоджено.
  5. Інтерфейс повідомляє про завершення лише після підтвердження збереженого стану.
  6. Якщо час уже недоступний, сервіс зберігає попередній запис і пояснює, як обрати інший.

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

45.3. Передумови й робочий бриф

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

Git-гілка є окремим вказівником на вершину історії комітів; її створення саме по собі не створює нового коміту. Команда git diff дозволяє порівняти зміну з індексом, робочим деревом або вибраною базою. Це дає зрозумілу межу для історії комітів та огляду, але сама гілка не відокремлює незбережені файли у спільному робочому дереві й не доводить правильність змін (git switch, git diff, перевірено 26 вересня 2026 року). Оглядач має знати точну базову ревізію: інакше diff може приховати наявну різницю або включити не пов’язану роботу.

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

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

Такий бриф стислий навмисно. Повна структура контракту, дозволів, передумов і звіту агента — предмет глави 46. Загальні поради OpenAI щодо Codex наголошують на конкретному завданні, релевантних шляхах і контексті; команда /review може подати пріоритетні висновки без зміни робочого дерева. У Claude Code режим plan не редагує файли до підтвердження, а команда /diff показує поточні зміни Git. Це продуктові можливості, що залежать від середовища й налаштувань; звіт агента не схвалює PR і не замінює перевірки репозиторію. Деталі перевірено 26 вересня 2026 року: OpenAI: робота з Codex, огляд коду в Codex, типові сценарії Claude Code, інтерактивний режим Claude Code.

45.4. Узгодженість даних і зручний зворотний зв’язок

Перенесення — не просто зміна підпису на екрані. Між тим, як клієнт побачив вільний час, і моментом збереження інший клієнт може забрати цей самий час. Сервер мусить повторно перевірити стан під час запису. Транзакція дає змогу групі змін зберегтися цілком або не зберегтися зовсім; у PostgreSQL блокування рядка SELECT … FOR UPDATE утримує вибраний рядок від конкурентної зміни до завершення транзакції. Але блокування самого бронювання не резервує порожній часовий інтервал. Для інтервалів перекриття потрібне окреме обмеження цілісності або відповідний механізм конкуренції на рівні сховища. Документація PostgreSQL показує для цього типів діапазонів обмеження-виключення, яке може заборонити перекриття інтервалів для того самого ресурсу. Якщо таке обмеження поєднує перевірку перекриття діапазону з рівністю простого ідентифікатора ресурсу в GiST-індексі, може знадобитися розширення btree_gist. Транзакція сама по собі бізнес-правила не створює (транзакції PostgreSQL, блокування рядків, типи діапазонів та обмеження, btree_gist). Точну модель статусів і доступності задає застосунок.

Короткий фрагмент SQL (Structured Query Language, мова структурованих запитів) нижче лише показує важливу різницю в умові пошуку. Це не готова реалізація: синтаксис, модель даних і стратегія конкуренції мають відповідати реальній системі.

-- Початковий небезпечний напрямок: ідентифікатора запису недостатньо.
SELECT id, owner_id, slot_id, status
FROM bookings
WHERE id = :booking_id
FOR UPDATE;

-- Потрібен фільтр за власником, якого визначив сервер із автентифікованого сеансу.
SELECT id, owner_id, slot_id, status
FROM bookings
WHERE id = :booking_id
  AND owner_id = :authenticated_user_id
  AND status = 'confirmed'
FOR UPDATE;

Клієнт не повинен визначати authenticated_user_id довільним параметром запиту: сервер отримує його з перевіреного контексту входу. Потім сервер перевіряє цільовий час і зберігає зміну в транзакції. Якщо правило недубльованих часових інтервалів закріплено обмеженням бази, конкурентна спроба має бути відхилена сховищем, а сервер перетворює цю відмову на зрозумілу відповідь API. Наприклад, код 409 Conflict у протоколі передавання гіпертексту (HTTP, Hypertext Transfer Protocol) може означати конфлікт з актуальним станом ресурсу; застосувати саме його до зайнятого часу — рішення контракту API, а не вимога стандарту HTTP 9110 (код 409). Так само метод PUT доречний лише якщо контракт справді описує заміну стану ресурсу бронювання; стандарт HTTP не визначає сам домен бронювань (метод PUT).

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

Стан Що бачить клієнт Що має зробити система
Завантаження «Перевіряємо доступні години…» Не дозволяти передчасно підтвердити невідомий варіант
Немає варіантів «Для цього періоду вільного часу немає» і зрозумілий вихід Зберегти чинне бронювання
Помилка або час уже зайнятий Пояснення без технічного жаргону; пропозиція оновити варіанти Не повідомляти про успіх і не втрачати попередній запис
Успіх Новий час, що відповідає збереженому стану Показати успіх лише після підтвердження сервера
Відновлення Доступна дія «спробувати знову» або повернення до вибору Повторити читання без дублювання небезпечної операції

Короткі, своєчасні пояснення й очевидний наступний крок узгоджуються з порадами Стіва Круга щодо зрозумілих сторінок і спостереження за тим, як люди проходять сценарій. Тут це орієнтир для тексту станів, а не доказ зручності конкретного інтерфейсу; останню треба перевірити з користувачами ([розділ 10, уривок Don’t Make Me Think](https://sensible.com/downloads/DMMTchapter10_for_personal_use_only.pdf), перевірено 24 вересня 2026 року).

45.5. Докази для приймання й повторна перевірка

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

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

Під час реалізації назви конкретні перевірки, фактичну команду й її код завершення. Наприклад, звіт має сказати: «На ревізії abc123 перевірка авторизації відхилила чужий booking_id; повторне читання підтвердило, що власник і час не змінилися». Якщо команда не запускалася, так і напишіть. Умовний вивід нижче — лише навчальний приклад того, як стисло пов’язати результат із критерієм; він не описує фактичний запуск:

Умовний прогін для навчального кейсу (не виконано на реальній системі)
власник + вільний час       PASS — повернуто новий час, повторне читання узгоджене
інший власник               PASS — зміни немає, чужі поля не повернуто
час уже зайнято             PASS — попередній запис збережено, показано конфлікт
після граничного часу       PASS — сервер відхилив перенесення
перегляд бронювання         PASS — попередній сценарій не зламано
інтеграція клієнт/сервер    PASS — обидві частини читають однаковий контракт

Незалежний огляд має порівняти зміну з початковим наміром, перевірити кожен критерій, прочитати негативний шлях і подивитися, чи не послаблено тест або правило доступу. Огляд конкретного diff від агента — корисний додатковий сигнал; рішення підтримувача репозиторію та його обов’язкові статуси — інші речі. На GitHub правила схвалення й обов’язкові перевірки залежать від конфігурації цільової гілки. Статусна перевірка може бути пропущена; позначка «успішно» також не доводить, що потрібна перевірка справді існувала. Тому записуйте, що реально налаштовано та виконано, а не робіть висновок лише з кольору індикатора (GitHub: огляди запитів на злиття, статусні перевірки, перевірено 26 вересня 2026 року).

45.6. Три навчальні випадки в межах одного зрізу

Нижче наведені три повні навчальні випадки. Усі назви бронювань, дані, результати прогонів і діалоги вигадані. Вони показують послідовність рішень, а не реальні запуски агента.

Випадок 1. Перенесення власного бронювання від запиту до огляду

Клієнтка Олена має підтверджений запис на четвер і хоче перенести його на п’ятницю. У заявці спочатку написано лише «дати можливість перенести бронювання». Автор уточнює власника, статус і часову межу, посилається на схему бронювання й узгоджений контракт API. За політикою цієї вигаданої системи можна переносити майбутній підтверджений запис до початку візиту. Запрошення до зміни оплати й повідомлення клієнтові в першій версії виключено.

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

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

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

Випадок 2. Оглядач знаходить пропущену перевірку власника

Під час першого огляду рецензент бачить запит до bookings за booking_id без прив’язки до автентифікованого користувача. На позитивних даних це виглядає правильно: Олена відкриває власний запис і бачить доступні години. Але інший клієнт може підставити в той самий запит ідентифікатор запису Олени. Якщо сервер довіряє лише ідентифікатору, запит може розкрити дані або змінити запис іншої людини. Це приклад порушення авторизації на рівні об’єкта (BOLA, Broken Object Level Authorization): кожен endpoint, що приймає ідентифікатор об’єкта й діє над ним, мусить перевірити право саме на цей об’єкт (OWASP (Open Worldwide Application Security Project, міжнародний проєкт із безпеки застосунків) API Security: API1:2023).

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

Випадок 3. Контракт API змінився перед злиттям

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

Це не розширення обсягу: зміна потрібна для тієї самої поведінки в актуальному контракті. Якщо ж старий контракт уже доступний зовнішнім споживачам, автор зупиняє злиття й передає власнику рішення про сумісність, період переходу або нову версію API. Така політика може змінити обсяг і ризик; агент не має непомітно випускати breaking change (несумісну зміну контракту) під виглядом локальної правки. PR оновлює список залежних перевірок і вказує, що змінився контракт. Рецензент перевіряє не лише рядки схеми, а відповідність усіх споживачів та фактичний інтеграційний результат.

45.7. Як читати реальний запит на злиття

У §19.14 ми вже звіряли обсяг змін і тести в реальному запиті FastAPI; тут фокус — на змісті коментарів рецензента й різниці між схваленням та злиттям.

У реальному запиті на злиття Django №21213 виправляють завантаження фікстури зі шляхом, що містить крапку. Звернення Django №37081 описує відтворювану проблему: шлях до теки на кшталт fix.v1 помилково розбирався як суфікс файлу. У файлах запиту видно зміну команди loaddata і перевірки для шляхів із крапкою, стиснених файлів, батьківських тек і початкової крапки. Раніше в обговоренні запропонували розібрати шлях через PurePath; у коментарі від 21 вересня інший рецензент запитав про складені суфікси, а автор пояснив різницю між .stem і чинним поділом суфіксів конкретним прикладом. Пізніший огляд містить схвалення. Станом на 26 вересня 2026 року PR залишався відкритим, попри схвалення, тож його не слід описувати як уже злитий чи випущений.

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

45.8. Злиття, розгортання й доступність користувачам

Запит на злиття в GitHub об’єднує опис, коментарі, огляди, коміти, порівняння змін і налаштовані перевірки. Рецензент може залишити коментар, схвалити зміну або запросити її виправити. Які схвалення й перевірки блокують злиття, визначають правила цільової гілки. Це налаштування процесу репозиторію, а не властивість кожного запиту на злиття (GitHub: про запити на злиття, як переглядати зміни, перевірено 24 вересня 2026 року).

Злиття додає зміни до цільової гілки. Розгортання доставляє конкретну версію до певного середовища. Випуск робить функцію доступною передбаченій групі користувачів — це може статися через реліз, конфігураційний перемикач, поступове відкриття чи інший контрольований процес. У деяких командах злиття автоматично запускає розгортання; це зв’язок, налаштований командою, а не обіцянка GitHub. Розгортання також може мати окремі правила середовища й погодження (GitHub: розгортання коду, середовища розгортання). Різницю між злиттям і випуском також показує §19.12; детальніша операційна робота з випуском розглядається у главах 56–60 та 68.

Перед тим як повідомляти «готово», назвіть стан точно:

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

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

45.9. Підсумок доказів і невизначеності

Для умовного перенесення бронювання цілісне свідчення складається з пов’язаних частин: узгодженої вимоги й межі, серверної перевірки власника, захисту від конфлікту за часом, зрозумілого стану інтерфейсу, позитивних та негативних перевірок, огляду актуального diff і точного статусу після злиття. Жодна окрема зелена перевірка, відповідь агента чи схвалення рецензента не є доказом усіх цих властивостей одразу.

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

Джерела й межі тверджень