Refaktoryzacja na dużą skalę z worktree w Codex
Refaktoryzacja na dużą skalę z Codex dzieli jedną zmianę zachowującą działanie kodu, rozlaną na setki plików, na spisany plan, fazę expand na jednej gałęzi i niezależne partie. Każda partia działa we własnym worktree Gita i trafia do main osobno. Niezmienione testy HTTP, zapadka licząca użycia starego API do zera i bramki CI dowodzą poprawności każdej partii.
Zespół zdecydował: przed kolejnym wydaniem API przechodzi z Express na Hono, a każde getUserById zmienia nazwę na findUser. To 300 plików w kilkunastu grupach tras. Jedna długo żyjąca gałąź oznacza zamrożenie kodu i review, którego nikt nie skończy. Ta strona jest dla developera, który prowadzi refaktoryzację w Codex, i dla tech leada, który musi zatwierdzić każdą partię bez czytania każdej zmienionej linii.
Strona dotyczy refaktoryzacji kodu, który ma już testy i zachowuje swoje działanie. Jeśli refaktoryzujesz legacy bez testów, zacznij od modernizacji legacy na dużą skalę z Codex. Mechanikę pojedynczego worktree (co przenosi, jak go sprzątnąć) opisuje strona izolowane zadania Codex w worktree Gita.
Co zyskujesz dzięki refaktoryzacji z Codex
Dział zatytułowany „Co zyskujesz dzięki refaktoryzacji z Codex”- Mapę zadań na powierzchnie Codex: co robi codemod, co sesja interaktywna, co partia w worktree, a co idzie do Codex cloud.
- Kolejność expand, migrate, contract, dzięki której
mainda się wdrożyć każdego dnia refaktoryzacji. - Skrypt zapadki i inwentarz tras, które mechanicznie dowodzą, że „nic się nie zmieniło”.
- Pięć promptów do skopiowania: plan, faza expand, partia, zmiana nazwy przez codemod i sprzątanie w fazie contract.
- Listę dowodów dla każdej partii, którą tech lead może podpisać, i sposoby wyjścia z typowych awarii.
Która powierzchnia Codex robi które zadanie refaktoryzacji?
Dział zatytułowany „Która powierzchnia Codex robi które zadanie refaktoryzacji?”Komendy poniżej sprawdziliśmy na codex-cli 0.157.1 (26.09.2026).
| Zadanie | Powierzchnia | Dlaczego tam |
|---|---|---|
| Zaplanowanie partii | Interaktywny codex w trybie planowania (/plan) | Przeglądasz graf zależności, zanim zmieni się jakikolwiek plik |
Czyste zmiany nazw (getUserById na findUser) | Skrypt codemod, który Codex pisze i uruchamia | Zmiana nazwy jest deterministyczna; skrypt nie pomija wywołań i nie improwizuje |
| Expand: wspólne middleware, adaptery | Interaktywny codex na jednej gałęzi bazowej | Wspólny kod potrzebuje jednego właściciela i twojej uwagi |
| Migracja grup tras | Osobny checkout git worktree add na partię, po jednej sesji codex | Partie idą równolegle i nie edytują nawzajem swoich plików |
| Contract: usunięcie Express | codex cloud exec --env ENV_ID --branch BRANCH | Długie, mechaniczne zadanie, które nie potrzebuje laptopa |
| Pierwsze review każdej partii | codex exec review --base BRANCH | Model recenzujący czyta diff, zanim zrobi to człowiek |
Krok 1: Zaplanuj refaktoryzację i zapisz plan w pliku
Dział zatytułowany „Krok 1: Zaplanuj refaktoryzację i zapisz plan w pliku”Równoległe partie wykładają się na wspólnych plikach, a nie na trudnym kodzie. Plan istnieje po to, by znaleźć każdy wspólny plik, zanim ruszy pierwsza partia. Uruchom codex w repozytorium, przełącz się w tryb planowania poleceniem /plan i wklej:
Czytaj listę właścicieli plików, nie prozę. Jeśli dwie partie potrzebują src/lib/session.ts, przenieś go od razu do fazy expand. Zacommituj plik planu na gałęzi bazowej refactor/hono-base, bo każdy prompt partii się do niego odwołuje.
Krok 2: Ustaw zapadkę i zamroź wyrocznię
Dział zatytułowany „Krok 2: Ustaw zapadkę i zamroź wyrocznię”Zanim przesunie się jakikolwiek kod, zapisz w komendach, co znaczy „zachowanie bez zmian”. Służą do tego dwa artefakty.
Wyrocznia. Testy HTTP w tests/http/ wysyłają prawdziwe żądania do aplikacji i sprawdzają kody statusu, nagłówki i treść odpowiedzi. Nie obchodzi ich, który framework odpowiada, więc w każdej partii muszą przechodzić bez zmian. Jedyny plik, którego partia może dotknąć, to bootstrap budujący aplikację pod testem.
Zapadka. Skrypt liczy pliki, które wciąż używają starego API. CI odrzuca zmianę, gdy liczba przekroczy zacommitowaną wartość bazową, a każda partia tę wartość obniża. Część dotycząca Express liczy tylko src/routes/: faza expand zostawia powłokę Express (src/app.ts, src/middleware/express/), która montuje Hono aż do fazy contract, więc licznik obejmujący całe src/ nie mógłby wcześniej spaść do zera:
#!/usr/bin/env bash# scripts/refactor-ratchet.sh: run in CI on every pull requestset -euo pipefailcount=$( { grep -rlE "from ['\"]express['\"]|require\(['\"]express['\"]\)" src/routes/ || true; grep -rl "getUserById" src/ || true; } \ | sort -u | wc -l | tr -d ' ')baseline=$(cat .refactor-baseline)echo "files on the old API: $count (baseline $baseline)"if [ "$count" -gt "$baseline" ]; then echo "old API usage went up"; exit 1fiWzorzec łapie oba style cudzysłowów i require(). Przed pierwszą partią uruchom skrypt i sprawdź, że licznik jest większy od zera: zero pierwszego dnia znaczy, że grep nie widzi twoich importów, a każda późniejsza kontrola przejdzie, niczego nie dowodząc.
Dodaj też inwentarz tras: scripts/print-routes.sh wypisuje posortowane metody i ścieżki wszystkich zarejestrowanych tras. Zacommituj jego wynik jako docs/refactor/routes.txt. Po każdej partii wynik musi być identyczny, co wyłapuje trasę usuniętą lub przemianowaną bez czytania jakiegokolwiek handlera.
Krok 3: Zbuduj fazę expand na jednej gałęzi
Dział zatytułowany „Krok 3: Zbuduj fazę expand na jednej gałęzi”Faza expand pozwala obu frameworkom obsługiwać ruch jednocześnie, więc każda partia trafia do aplikacji, którą da się wdrożyć. @hono/node-server (2.1.1 w npm, 26.09.2026) eksportuje getRequestListener, który zamienia aplikację Hono w handler żądań Node, a ten Express może zamontować pod prefiksem. Zostań na refactor/hono-base i wklej:
Jedna pułapka montowania: Express usuwa prefiks montowania z req.url, zanim wywoła zamontowany handler, więc pod /auth aplikacja Hono widzi /login, a nie /auth/login, i trasa Hono zdefiniowana z pełną ścieżką zwraca 404. Definiuj trasy Hono względem prefiksu montowania albo zamontuj listener bez ścieżki (app.use((req, res) => listener(req, res))), żeby Hono widziało pełne ścieżki; zarejestruj go po wszystkich trasach Express, jako ostatnie middleware, bo odpowiada na każde żądanie, które do niego dotrze. Testy HTTP i diff inwentarza tras wyłapią oba błędy.
Zmerguj tę gałąź do main, zanim ruszą partie. Od tej chwili main działa na obu frameworkach i pozostaje gotowy do wdrożenia.
Krok 4: Uruchom każdą partię we własnym worktree
Dział zatytułowany „Krok 4: Uruchom każdą partię we własnym worktree”Dla każdej grupy tras utwórz nazwaną gałąź i osobny checkout ze zmergowanej bazy. W terminalu, raz na partię:
git fetch origingit worktree add -b refactor/hono-auth ../api-hono-auth origin/maincd ../api-hono-auth && npm ci && codexcodex --worktree tworzy zamiast tego zarządzany worktree, ale na odłączonym HEAD. Gdy praca ma skończyć się nazwanym pull requestem, prostsza jest forma git worktree add -b. Wklej ten sam prompt w każdej sesji i zmieniaj tylko nazwę grupy:
Jeśli wolisz uruchamiać partie ze skryptu, codex exec -C DIR wykona ten sam prompt nieinteraktywnie w każdym checkoucie. Skrypt rozdzielający pracę i limit równoległych torów znajdziesz na stronie przepływy wieloagentowe w Codex.
Zmień nazwę w całym kodzie codemodem, nie ręcznie
Dział zatytułowany „Zmień nazwę w całym kodzie codemodem, nie ręcznie”Zmiana nazwy dotyka setek wywołań i nie wymaga osądu, więc zadaniem agenta jest napisać narzędzie, a nie być narzędziem. Agent poprawiający ręcznie 400 wywołań może jedno pominąć; skrypt albo obsłuży każde dopasowanie, albo się na nim wywróci. Uruchom to we własnym worktree i w chwili, gdy żadna partia nie jest otwarta: w ramach fazy expand, zanim ruszą partie, albo po zmergowaniu ostatniej partii, a przed fazą contract. Nigdy nie uruchamiaj tego równolegle z partiami, bo codemod edytuje pliki, które plan przypisuje poszczególnym partiom.
Recenzent czyta wtedy 40-linijkowy skrypt zamiast diffu na 400 plików i może go uruchomić ponownie na nowszej bazie, jeśli gałąź się zestarzeje.
Krok 5: Merguj partie pojedynczo
Dział zatytułowany „Krok 5: Merguj partie pojedynczo”Merguj w kolejności z planu, po jednej partii na pull request, i daj CI przejść między mergami. Po każdym mergu zrób rebase otwartych partii na nowy main i uruchom ponownie ich bramki: zmiana middleware w jednej partii potrafi zepsuć treść błędów w innej. Poproś Codex w worktree po rebase:
Rebase this branch onto origin/main. Resolve conflicts by keeping main's version of any filethis batch does not own. Then rerun every command from the batch prompt and report the results.Krok 6: Przeprowadź fazę contract w Codex cloud
Dział zatytułowany „Krok 6: Przeprowadź fazę contract w Codex cloud”Gdy zapadka pokazuje zero, żadna trasa ani żadne wywołanie nie używa już starego API. Zostaje powłoka Express, którą plan wymienia w sekcji CONTRACT (src/app.ts, src/middleware/express/), a jej usunięcie jest mechaniczne. Codex cloud klonuje repozytorium z remote’a, więc najpierw zrób push i podaj gałąź jawnie. W terminalu, gdzie ENV_ID to identyfikator lub etykieta twojego środowiska Codex cloud:
git fetch origingit push origin origin/main:refs/heads/refactor/hono-contractcodex cloud exec --env ENV_ID --branch refactor/hono-contract < docs/refactor/contract.mdcodex cloud exec bez argumentu czyta prompt ze standardowego wejścia i wypisuje adres URL zadania; diff i apply przyjmują URL albo sam identyfikator z jego końca. Komenda git push tworzy zdalną gałąź bez przełączania twojej kopii roboczej, więc worktree poniżej dostaje nazwaną gałąź, na której zacommitujesz nałożony diff. Obejrzyj i nałóż wynik w czystym checkoucie, a nie w swojej kopii roboczej:
codex cloud diff TASK_URLgit fetch origingit worktree add -b refactor/hono-contract-apply ../api-hono-contract origin/refactor/hono-contractcd ../api-hono-contract && codex cloud apply TASK_URLnpm ci && npm run typecheck && npm test--attempts od 2 do 4 zamawia kilka niezależnych prób; przy mechanicznym sprzątaniu zwykle wystarcza jedna. Zobacz, kiedy best-of-N jest wart swojej ceny.
Jak zweryfikować partię refaktoryzacji bez czytania każdej linii?
Dział zatytułowany „Jak zweryfikować partię refaktoryzacji bez czytania każdej linii?”Refaktoryzacja jest poprawna, gdy obserwowalne zachowanie się nie ruszyło. Każda partia dowodzi tego tym samym zestawem dowodów, zebranym komendami, a nie czytaniem:
-
Wyrocznia się nie ruszyła.
git diff --stat origin/main...HEAD -- tests/http/jest pusty albo pokazuje tylkotests/http/setup.ts. -
Bramki przechodzą w CI, a nie tylko w raporcie agenta:
npm run typecheck,npm run lintinpm test. -
Zapadka spadła.
scripts/refactor-ratchet.shpokazuje mniej plików, a.refactor-baselineobniżono w tym samym pull requeście. -
Inwentarz tras jest identyczny. Diff względem
docs/refactor/routes.txtjest pusty. -
Automatyczny recenzent przeczytał diff pierwszy. W worktree partii uruchom:
Okno terminala codex exec review --base origin/mainOpcji
--basenie da się połączyć z własnymi instrukcjami recenzji (sprawdzone w codex-cli 0.157.1: komenda kończy się błędemthe argument '--base <BRANCH>' cannot be used with '[PROMPT]'). Gdy chcesz nadać recenzji własny kierunek, uruchom/revieww interaktywnej sesji partii albo przekaż diff zwykłemucodex exec, który dołącza standardowe wejście do promptu:Okno terminala git diff origin/main...HEAD | codex exec "Flag any behavior change: status codes, headers, error bodies, middleware order, or edits outside this batch's files. Say NO FINDINGS if there are none."Na pull requeście to samo robi
@codex review. Zobacz code review z Codex. -
Konkretna osoba podpisuje. Właściciel partii merguje na podstawie powyższych dowodów. Partie z uwierzytelnianiem i rozliczeniami dostają dodatkowo ludzką lekturę handlerów, zgodnie z zasadą czytania dowodów zamiast kodu.
-
Produkcję da się cofnąć. Każda partia wychodzi osobnym wdrożeniem, więc regresja cofa jedną grupę tras, a nie całą refaktoryzację.
Umieść dowody w opisie pull requesta, żeby zatwierdzający nie musiał niczego uruchamiać ponownie. Format podaje strona o pakiecie dowodów, który musi przynieść pull request agenta.
Gdy duża refaktoryzacja w Codex się sypie
Dział zatytułowany „Gdy duża refaktoryzacja w Codex się sypie”| Objaw | Przyczyna | Naprawa |
|---|---|---|
| Dwie partie mają konflikt w tym samym pliku | Plan przeoczył wspólny import | Zmerguj pierwszą partię, zrób rebase drugiej i przenieś plik do fazy expand w planie. Przed kolejną falą powtórz sprawdzenie wspólnych plików z promptu planującego |
| Partia jest zielona, bo zmienił się test | Agent osłabił asercję, by pasowała do nowego zachowania | Pusty diff tests/http/ blokuje merge. Uruchom ponownie z „fix the implementation, never the test” na początku promptu |
| Testy przechodzą w każdym worktree, ale padają po dwóch mergach | Każda partia działała na bazie bez zmian drugiej | Po każdym mergu rób rebase otwartych partii i uruchamiaj ich bramki, jak w kroku 5 |
| Odpowiedzi z błędem zmieniają kształt po migracji | Domyślna obsługa błędów w Hono różni się od middleware błędów w Express | Dodaj test charakteryzacyjny dla treści błędu, potem przenieś handler błędów w fazie expand, a nie w partii |
| Zmiana nazwy pominęła wywołania albo zmieniła nazwę niewłaściwej funkcji | Agent edytował ręcznie albo dopasowywał tekst zamiast typów | Cofnij zmianę i uruchom prompt z codemodem: skrypt świadomy typów, najpierw liczba z dry-run |
Licznik zapadki rośnie na main | Gałąź funkcjonalna kolegi dodała nowe trasy w Express | CI to blokuje; poproś o trasę w Hono albo podnieś wartość bazową świadomie, w commicie po review |
| Zadanie w chmurze nie widzi aplikacji Hono | Gałąź nie została wypchnięta albo pominięto --branch i zadanie ruszyło na bieżącej gałęzi lokalnej | Najpierw push, potem jawne --branch |
| Commity zniknęły razem z usuniętym worktree | Zarządzany worktree na odłączonym HEAD usunięto, zanim jego commity trafiły na gałąź; jego reflog zniknął razem z nim | Zanim ruszy git gc, uruchom git fsck --lost-found, znajdź swój commit przez git show SHA, a potem git branch rescue/BATCH SHA. Zapobiegaj temu, zawsze tworząc nazwaną gałąź (git worktree add -b); zobacz przewodnik po worktree w Codex |
Dokąd dalej po refaktoryzacji w Codex
Dział zatytułowany „Dokąd dalej po refaktoryzacji w Codex”Ten sam przepływ w innych narzędziach: refaktoryzacja z Claude Code i strategie refaktoryzacji w Cursorze.