JavaRush /Курси /Claude code /Перевірка на основі diff, L1 review

Перевірка на основі diff, L1 review

Claude code
Рівень 18 , Лекція 4
Відкрита

1. Дивимося не на пояснення, а на diff

До цього моменту зміна вже зібрана: root cause зафіксовано, regression evidence під рукою, diff розкладено на коміти, а PR_DESCRIPTION.md пояснює суть. Але це ще не означає, що PR можна мовчки відправляти далі. Тести зелені, Claude бадьоро пише «готово, все працює» — і саме тут тягне розслабитися. Інженерна дисципліна починається там, де хочеться закрити ноутбук.

У diff є дуже корисна властивість: він не розповідає історію, а показує факт зміни. Diff — це касовий чек вашої правки: потім не сперечаються, що саме ви «купили» у коду і чому в кошику опинилися ще три зайві файли.

Раніше ми читали маленький diff після кожного кроку, щоб тримати implementation loop під контролем. Тут масштаб інший: мають збігатися файли, коміти, walkthrough та evidence — review усього зміни, а не перевірка мікрокроку.

Тут корисно на секунду нагадати різницю між verification і review: перше відповідає на «чим ми довели коректність», друге — «хто подивився і ухвалив локальне рішення». Нас цікавить review-шар.

Що порівнюємо На яке питання відповідає
Verification Що ми запускали, чим перевіряли, які тести й команди дали evidence
Layer 1 review Хто подивився на diff, що помітив і чому вирішив, що PR готовий або не готовий

Щоб не говорити надто абстрактно, візьмемо наскрізний приклад із Commerce OS. Баг: порожній кошик призводив до 500 при checkout. Approved plan мав такий вигляд:

## Затверджений план

1. Додати guard для порожнього кошика в `OrderController`.
2. Додати regression test у `OrderControllerTest`.
3. Не змінювати інші endpoints і не чіпати логіку `/orders/preview`.

А ось фрагмент реального diff:

public OrderResponse checkout(@RequestBody CheckoutRequest request) {
+   if (request.items() == null || request.items().isEmpty()) {
+       throw new InvalidRequestException("Кошик порожній");
+   }
+   return checkoutService.checkout(request.items());
}

Від цього моменту ваше завдання — не радіти тому, що «guard же додали», а поставити спокійні інженерні питання. Чи збігається це з approved plan? Чи не поїхав diff кудись іще? Чи змінили поведінку ширше, ніж збиралися? Чи є тест? Чи не зламали сусідній шлях? Ось точка входу в локальне review.

2. Склад Layer 1 review

Саме слово review іноді звучить лячно, ніби зараз прийде сердитий сеньйор, побачить зайвий рядок і відправить переписувати кар’єру. Насправді Layer 1 review — це локальна послідовність кроків, яка не дає випустити сирий PR і робить його чистим та пояснюваним уже з вашого боку. Зручно бачити його як маленький конвеєр:

flowchart TD
    A[Approved plan + diff] --> B[Self-review]
    B --> C[Claude-assisted review]
    C --> D[Fresh-context review]
    D --> E[Review notes]
    E --> F[Human decision]

Якщо в проєкті вже схвалено якийсь review-плагін, його можна вбудувати між fresh-context review та підсумковим рішенням. Але важливо не плутати інструмент із суддею: плагін або Claude допомагають помітити проблему, а не ухвалюють рішення замість вас.

Нижче — вся логіка в одній таблиці.

Крок Хто дивиться Навіщо потрібен Що виходить на виході
Self-review Ви як автор Перевірити, чи збігається diff із планом і змістом задачі Первинна локальна оцінка diff
Claude-assisted review Claude у writer-сесії або окремому запиті Швидко підсвітити scope creep, missing tests, edge cases Список знахідок із рівнем важливості
Fresh-context review Інша сесія або reviewer-subagent Зняти замиленість автора та confirmation bias Другий погляд без авторської історії
Plugin-assisted review Опційно, якщо plugin уже схвалено Додати ще один автоматизований прожектор Додаткові зауваження
Хмарне ревʼю Опціональний прискорювач: багатоагентний розбір складного diff у хмарі Отримати розширений контекст і відразу кілька спеціалізованих поглядів Єдиний звіт зі зведеними знахідками
Human decision Ви або живий ревʼюер Ухвалити рішення: готово, виправляємо, ділимо PR Свідомий go / no-go

Найважливіше тут — порядок: спочатку ви самі читаєте свій diff, потім підключаєте Claude, потім даєте diff «свіжій голові», і тільки потім формуєте REVIEW_NOTES.md. Пропустіть self-review, одразу запитавши модель «ну як там?» — і ви призначаєте Claude своїм заступником з відповідальності. Погана кадрова політика.

3. Self-review: спочатку ви, потім уже Claude

Self-review здається нудним рівно до першого разу, коли ви знаходите у своєму PR зайвий файл, випадковий rename або правку «заодно», яку вчора навіть не помітили. Він знімає найдешевші помилки — ті, що потім прикро ловити на чужому review.

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

git diff --stat                                 # швидко дивимося масштаб змін
git diff src/orders/OrderController.java        # читаємо зміст production-правки
git diff src/orders/OrderControllerTest.java    # окремо перевіряємо regression test
git status                                      # чи немає випадково зайвих файлів

Тепер корисно звіряти diff із approved plan майже як за чек-листом, але без бюрократичного фанатизму.

Що звіряємо Яке питання ставимо собі
Список файлів Усі ці файли справді були в плані?
Поведінка Чи виправляю я саме той сценарій, заради якого відкрив задачу?
Тести Чи є явний regression test або хоча б оновлена перевірка?
Scope Чи не торкнувся я сусідніх endpoint'ів, конфігів або рефакторингу «за компанію»?
Читабельність Чи можу я пояснити цей diff за хвилину без фрази «ну тут Claude сам вирішив»?

Припустімо, крім guard у OrderController ви раптом бачите ще й зміну в OrderPreviewController. Ось тут self-review і має вас зупинити: Claude «хотів допомогти» — зробити поведінку однаковою, але approved plan прямо сказав /orders/preview не чіпаємо. Це не покращення, а scope creep.

Корисно також дивитися не лише на додані та вилучені рядки, а й на змінений зміст. Наприклад, ось маленький тест:

import org.junit.jupiter.api.Test;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@Test
void rejectsEmptyCart() throws Exception {
    mockMvc.perform(post("/api/orders")
            .contentType("application/json")
            .content("{\"items\":[]}"))
        .andExpect(status().isBadRequest());
}

Сам по собі він виглядає добре. Але self-review підштовхує до ще одного питання: тест закриває стару болючу точку з root cause — чи ми просто повісили зелену лампочку на схожий сценарій? Якщо баг проявлявся на HTTP-рівні, а тест іде лише у внутрішній exception, частина проблеми все ще поруч. Фінальна самоперевірка: якби цей PR відкрив не я, а колега, чи зміг би я за diff швидко зрозуміти, що сталося і навіщо? Відповідь «приблизно, але довелося б згадувати контекст чату» означає — PR ще сируватий.

4. Claude-assisted review: правильний фокус

Після self-review дуже зручно підключити Claude як другого читача diff. Але тут є тонка пастка: запитайте просто «перевір PR» — і модель почне допомагати занадто широко. А «занадто широко» в review майже завжди означає «занадто розмито». Давайте Claude не свободу, а фокус:

Перевір поточний diff проти approved plan.
Дивися тільки на:
- розповзання scope,
- відсутні тести,
- крайні випадки,
- зворотну сумісність,
- чутливі зміни у валідації,
- неясні місця в коді.
Згрупуй знахідки за важливістю: blocker / major / minor.
Вкажи file:line, якщо це можливо.
Файли не редагуй.

Тут важливі одразу три речі: зв’язок з approved plan, список зон уваги, заборона на редагування. Вам зараз потрібен reviewer, а не «ревʼюер, який про всяк випадок уже все сам виправив». Claude в цьому режимі швидко сканує diff і приносить список гіпотез, які ви далі або підтверджуєте, або відхиляєте.

Рівень Що означає Як зазвичай реагуємо
Blocker PR не можна вважати готовим Виправляємо до будь-якого руху далі
Major Суттєвий ризик або помітний пропуск Зазвичай правимо в цьому ж PR
Minor Покращення читабельності, назви, формулювання Виправляємо за ситуацією

Уявімо, що Claude повернув major/orders/preview і надалі дозволяє порожній кошик») і minor («назву тесту rejectsEmptyCart можна точніше»). Але це ще не вирок: ви читаєте, співвідносите зі scope і вирішуєте.

Дуже корисна звичка — фіксувати не лише прийняті, а й відхилені зауваження. Тому що Claude іноді звучить так упевнено, ніби вже сам собі схвалив PR і пішов за кавою. А частина зауважень може не мати стосунку до поточного scope.

## Claude-assisted ревʼю

- Major: endpoint `/orders/preview` не покрито новою валідацією — прийнято, відкриваємо follow-up issue
- Minor: тест `rejectsEmptyCart` можна перейменувати на `returnsBadRequestForEmptyCart` — прийнято
- Minor: додати логування в controller — відхилено, поза scope поточного PR

Так review перестає бути розмитою розмовою «щось десь не сподобалося» і стає набором рішень. А рішення люблять, коли їх записують.

5. Fresh-context review: свіжий погляд

Після кількох годин роботи над однією задачею відбувається дуже людська річ: ви бачите в diff не те, що написано, а те, що хотіли написати. Саме тому fresh-context review так корисний — це не недовіра до себе, а нормальна інженерна вакцина від замиленого погляду.

Найпростіший варіант — відкрити нову Claude-сесію й дати їй лише потрібні артефакти: approved plan, PR_DESCRIPTION.md, diff і test plan. Ще зручніше reviewer-subagent із Workflow Kit — заново ми його не налаштовуємо, просто використовуємо як свіжу пару очей.

Ти — reviewer зі свіжим контекстом.
У тебе немає історії writer-сесії.
Перевір поточний diff проти approved plan і PR walkthrough.
Сфокусуйся на:
- невідповідності plan ↔ diff,
- пропущених крайніх випадках,
- неочевидних змінах поведінки,
- тестових прогалинах.
Поверни findings із важливістю та коротким обґрунтуванням.
Файли не редагуй.

Чому fresh-context review працює краще, ніж «той самий Claude, але ще раз»? Тому що writer-сесія вже накопичила історію рішень, гіпотез, відхилених шляхів та емоційне відчуття «ну я ж знаю, що тут відбувається». Нова сесія цього багажу не має — вона дивиться на PR так само, як потім подивиться живий ревʼюер.

У нашому прикладі з Commerce OS свіжий reviewer помічає те, що writer уже перестав бачити: walkthrough обіцяє HTTP 400 для POST /api/orders, а в перевірках поруч вказано лише targeted test. Ручну HTTP-перевірку справді проганяли — чи її треба додати в evidence, чи прибрати з walkthrough? Це і є золото fresh-context review.

Якщо diff помітно багатошаровий — зачіпає безпеку, тести й продуктивність одночасно, — можна зробити ще один крок і запустити кілька спеціалізованих reviewer-агентів паралельно: один на security-кутик, другий на тести, третій на архітектуру. Але це вже опція, а не обов’язок: для більшої частини PR вистачить одного свіжого reviewer'а.

І ще одна важлива думка: свіжий reviewer не має перетворюватися на «третейського суддю, який завжди правий». Він приносить новий сигнал. Рішення за сигналом усе ще залишається за людиною.

6. REVIEW_NOTES.md і людське рішення

Коли self-review, Claude-assisted review і fresh-context review завершені, важливо не залишити результат розпорошеним по чату, пам’яті й вкладках термінала. У цей момент з’являється другий головний артефакт лекції — REVIEW_NOTES.md. Якщо PR_DESCRIPTION.md розповідає ревʼюеру що і навіщо ви змінили, то REVIEW_NOTES.md фіксує, як саме ви локально перевіряли PR і до чого дійшли.

# REVIEW_NOTES.md

## Self-review
- diff збігається з кроками approved plan
- змінено лише `OrderController` і `OrderControllerTest`
- unrelated files відсутні

## Claude-assisted ревʼю
- Minor: перейменувати тест для більшої ясності — прийнято
- Major: перевірити узгодженість із `/orders/preview` — follow-up issue створено

## Ревʼю на свіжому контексті
- підтверджено: scope не розповзся
- знайдено: manual check у PR walkthrough варто уточнити — прийнято

## Фінальне рішення
PR готовий до відправлення на зовнішній review.
Відкриті follow-up задачі не блокують поточний bugfix.

Зверніть увагу на останню секцію. Вона називається не «схвалено Claude», не «все чудово» і не «ну начебто можна». Вона називається Final decision. Тому що саме тут закінчується локальна автоматизація і починається людська відповідальність.

По суті, розумних рішень зазвичай чотири. PR готовий. Або потребує ще одного невеликого виправлення. Або його краще розбити на два — diff виріс або затесалася зайва ідея. Або review повертає вас у debugging: root cause описано слабко. Усі чотири нормальні. Ненормальним є лише пʼятий: «нічого не зрозумів, але гаразд, відправлю так».

Людське рішення і є точка, в якій локальний Layer 1 review закінчується. У вас чистий diff, зрозумілий PR_DESCRIPTION.md, зафіксований REVIEW_NOTES.md, список прийнятих і відхилених зауважень. Три погляди — свій, Claude і свіжий контекст — уже відсіяли зайві файли, scope creep і діри в тестах, але останнє слово залишилося не за ними. Self-review, Claude і fresh-context лише підсвічують проблеми; рядок Final decision пишете ви. І саме цей підпис, а не зелені галочки інструментів, перетворює «те, що Claude десь нагенерував», на зміну, за яку відповідає людина.

7. Хмарне ревʼю як прискорювач

Хмарне ревʼю — це природне продовження ревʼю зі свіжим поглядом для випадків, коли локального reviewer-subagent уже не вистачає. Запускається однією командою (умовно /ultrareview або подібна хмарна команда; точна назва й доступність можуть змінюватися від версії до версії). Ментальна модель та сама: це те саме ревʼю зі свіжим поглядом, що й у кроці fresh-context, тільки винесене в хмарне середовище.

Чим це відрізняється від багатоагентного ревʼю, яке ви й так можете підняти локально з Workflow Kit? Розширеним контекстом. На один і той самий diff паралельно дивляться кілька спеціалізованих агентів — із безпеки, продуктивності, тестів і архітектури, — і все зводиться в розмічений diff зі знахідками, посиланнями на файли та рівнем серйозності. Звіт лягає в той самий REVIEW_NOTES.md, що й звичайні знахідки.

Коли хмарне ревʼю доречне

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

Кожен запуск ultrareview оплачується окремо і коштує від $5 до $25 залежно від розміру. Знати, що цей інструмент існує, важливо; запускати його на кожен PR — ні.

Коли хмарне ревʼю недоречне

І стільки ж ситуацій, де хмарне ревʼю тільки заважає. Маленький PR із очевидним diff — витрати й затримка більші за виграш. Репозиторій або дані не можна вивантажувати в хмару — чутливі дані або регульоване середовище: питання політики, а не якості ревʼю. Ви не зможете осмислено прочитати знахідки постфактум — хмарне ревʼю не скасовує обов’язку читати diff і ухвалювати рішення. Терміновий hotfix — на розбір звіту немає часу.

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

І насамкінець — головне правило, яке не змінюється на жодному рівні ревʼю: AI-ревʼю будь-якого рівня — від self-review до хмарного — допомагає знайти проблеми, але не замінює читання diff і відповідальність розробника.

1
Опитування
Реалізація, налагодження та review з Claude, рівень 18, лекція 4
Недоступний
Реалізація, налагодження та review з Claude
Реалізація, налагодження та review з Claude
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ