Przejdź do głównej zawartości

Programowanie sterowane błędami

Programowanie sterowane błędami traktuje każdy błąd kompilatora, nieudany test lub wyjątek w runtime jako precyzyjną, wygenerowaną maszynowo specyfikację: mówi ona, co jest źle, gdzie i czego system oczekiwał zamiast tego. Pętla polega na wprowadzeniu zmiany, uruchomieniu weryfikacji, przekazaniu agentowi pierwszego błędu z docelowym kontekstem i naprawieniu jego przyczyny źródłowej.

CI świeci na czerwono. Czternaście błędów TypeScript, trzy nieudane testy i ostrzeżenie o deprecjacji. Stack trace wskazuje na payment.ts:212, spaliłeś już dwadzieścia minut na zgadywaniu, który z ostatnich sześciu commitów to zepsuł, a poprawka, którą właśnie wypchnąłeś, zamieniła jeden nieprzechodzący test w trzy. Wpatrywanie się w błąd mocniej nie działa.

Oba instynkty, które się teraz odzywają, są złe. Naprawianie wszystkiego ręcznie ignoruje to, w czym agent jest naprawdę dobry. Wklejenie całego loga z dopiskiem „napraw wszystko” daje mu zbyt wiele naraz i produkuje kaskadowe „naprawy”, które wprowadzają nowe problemy.

Komunikat błędu to najprecyzyjniejsza specyfikacja tego, co jest nie tak, jaką masz — i dokładnie ten rodzaj wejścia, który asystent AI konsumuje najlepiej, lepszy niż jakikolwiek prompt napisany od zera. Programowanie sterowane błędami to wykorzystuje: zamiast celować w idealny pierwszy szkic, uruchamiasz ciasną pętlę błąd → naprawa → restart i pozwalasz każdej awarii sterować kolejną zmianą. Robione świadomie, zbiega szybko nawet na paskudnych kaskadach.

  • Powtarzalną pętlę błąd-naprawa-restart, którą uruchomisz w każdym z trzech narzędzi
  • Gotowe prompty na produkcyjny stack trace, kaskadę kompilatora i pętlę z nieprzechodzącym testem
  • Mechanikę każdego narzędzia: kto uruchamia testy, kto cofa złą poprawkę, kto iteruje bez nadzoru
  • Wyjście awaryjne, gdy naprawienie jednego błędu wciąż produkuje trzy kolejne
  • Skrót przez MCP, który pobiera zgłoszenie z Sentry zamiast kopiowania stack trace’ów
  • Nawyk zamiany trudno wywalczonej poprawki w regułę w CLAUDE.md, .cursor/rules albo AGENTS.md

Zamiast próbować zapobiec wszystkim błędom, oprzyj się na nich jako najszybszym dostępnym mechanizmie sprzężenia zwrotnego:

  1. Wprowadź zmianę (lub pozwól agentowi ją wprowadzić)
  2. Uruchom krok weryfikacji (build, test, lint, type-check)
  3. Przeczytaj pierwszy błąd
  4. Przekaż go agentowi z docelowym kontekstem
  5. Pozwól agentowi naprawić przyczynę źródłową
  6. Powtórz od kroku 2

Kluczowa dyscyplina to jeden błąd na raz. Komunikaty błędów kaskadują: jedna przyczyna źródłowa produkuje dziesiątki dalszych błędów, a naprawienie pierwszego zwykle sprawia, że połowa pozostałych znika. Naprawianie błędu numer czternaście, gdy numer jeden wciąż tam jest, to zmarnowana praca.

Cykl jest wszędzie identyczny — ujawnij błąd, daj agentowi dość kontekstu, zastosuj poprawkę, uruchom ponownie dokładnie to, co zawiodło. Różni się to, kto uruchamia polecenie i jak wycofujesz złą poprawkę.

W trybie agenta Cursor sam uruchamia testy albo build, czyta wyjście terminala i iteruje bez kopiowania przez ciebie — po nieudanym poleceniu możesz po prostu powiedzieć „fix the error in the terminal”. Siatką bezpieczeństwa są punkty kontrolne: każda edycja agenta to punkt przywracania, więc gdy poprawka pogarsza sprawę, wracasz jednym kliknięciem do ostatniego zielonego stanu, zamiast to rozplątywać.

Gdy już wklejasz błąd, wklej go z kontekstem, który czyni go wykonalnym:

I ran npm run type-check and got this error:
src/services/notification.ts:42:5 - error TS2345:
Argument of type 'string' is not assignable to parameter
of type 'NotificationPayload'.
Fix the root cause. The function signature in @src/services/notification.ts
expects a NotificationPayload object, not a raw string. Check the caller
at line 42 and the type definition in @src/types/notification.ts.

Najlepsze, gdy chcesz obserwować pętlę i wtrącić się w momencie, gdy zacznie zbaczać.

Użytkownik trafił na crash, a twój error tracker przechwycił wyjątek. Najszybsza droga to podać agentowi trace razem z plikami, które wskazuje — pełny wyjątek i stos, nie samą górną linię, bo górna ramka to miejsce, w którym wartość została odczytana, a rzadko to, w którym coś poszło źle.

Poprawka powinna sięgnąć tam, gdzie total stało się undefined — na przykład do koszyka bez pozycji wyżej w przepływie — a nie dokleić ?. w linii 212. Uruchom ponownie nieudaną ścieżkę; jeśli wypłynie nowy błąd, podaj go z powrotem i powtórz.

Zmieniłeś sygnaturę kluczowej funkcji i type-checker zapalił się trzydziestoma błędami w całej bazie kodu. To słodki punkt tej pętli, bo błędy są dokładną, wygenerowaną maszynowo listą roboczą. Nie naprawiaj najpierw niczego ręcznie; pozwól liście się zmaterializować, a potem oddaj całość.

Agent poprawia miejsca wywołań, uruchamia ponownie type-checker i powtarza. Godzina mordęgi ręcznej kończy się w kilku cyklach, bo agentowi nigdy nie nudzi się przy dwudziestym siódmym miejscu wywołania.

Najmocniejsza forma tej pętli to napisanie nieprzechodzącego testu na początku i pozwolenie agentowi, by sam doprowadził się do zieleni. Test jest jednoznaczną wyrocznią, więc pętla kończy się sama.

To ostatnie zdanie ma znaczenie. Bez niego nadgorliwy agent czasem „naprawi” awarię, rozluźniając asercję. Przypnij test jako specyfikację.

Lista robocza kompilatora kurczy się w miarę pracy. Groźny rodzaj kaskady robi odwrotnie: agent naprawia błąd 1, co wprowadza błąd 2, którego naprawa wprowadza błąd 3, a ty spalasz okno kontekstu na grę w kreta. Sygnałem jest ten sam plik pojawiający się w każdej rundzie. Gdy tak się dzieje, przestań naprawiać błędy i zabierz się za strukturę.

Gdy ten sam plik wraca raz za razem, odsuń kamerę:

We've been fixing errors in notification.ts for three iterations
and new ones keep appearing. Stop fixing individual errors.
Instead:
1. Read the full file @src/services/notification.ts
2. Read the types it depends on @src/types/notification.ts
3. Read the test file @src/services/__tests__/notification.test.ts
4. Identify the structural problem causing the cascade
5. Propose a fix for the root architectural issue
Do not modify any files until I approve the approach.

Najcenniejsze błędy to te, których nigdy więcej nie zobaczysz. Gdy błąd okazuje się nieoczywisty, zapisz lekcję w konfiguracji projektu, żeby agent unikał tej samej pomyłki w każdej kolejnej sesji.

Dodaj regułę projektu w .cursor/rules/errors.md:

---
description: "Common errors and their fixes for this project"
alwaysApply: true
---
## Known Error Patterns
- When modifying notification types, always update both
`src/types/notification.ts` AND the Zod schema in
`src/validators/notification.ts`. They must stay in sync.
- Redis connection errors in tests: run `docker compose up -d redis`
before running the test suite.
  • Gonienie za niewłaściwym błędem w kaskadzie. Pierwszy błąd często powoduje resztę. Powiedz agentowi, żeby naprawił najwcześniejszy, źródłowy błąd i uruchomił ponownie, zanim ruszy pozostałe.
  • Naprawianie objawu, nie przyczyny. Owinięcie dostępu do undefined w ?. zatrzymuje crash, ale nie wyjaśnia, czemu wartości brakowało. Pytaj „gdzie to stało się undefined?”, a nie „zatrzymaj wyrzucenie”.
  • Agent tłumi zamiast naprawiać. @ts-ignore, as any, puste bloki catch i eslint-disable w wyjściu oznaczają zarządzanie objawami. Bądź bezpośredni: nie tłum błędów, napraw przyczynę.
  • Wieczna pętla na niestabilnym teście. Niedeterministyczna awaria pozwala agentowi „naprawić”, uruchomić ponownie, zobaczyć zieleń i ogłosić zwycięstwo — a potem znów sypie się w CI. Najpierw zakwarantannij niestabilny test; nie uruchamiaj na nim tej pętli.
  • Furtka edycji testu. Agenci czasem przepuszczają niezdaną asercję, osłabiając ją. Dodaj „do not modify the test” do każdego promptu sterowanego testami.
  • Ślepota kontekstowa. Wklejenie samej górnej ramki stosu ukrywa prawdziwego winowajcę głębiej w trace’ie. Daj pełny trace i nazwij podejrzane pliki.
  • Zbyt wiele błędów do przetworzenia. Gdy type-checker produkuje 200+ błędów, nie podawaj ich wszystkich. Przerób pierwsze trzy do pięciu — to zwykle przyczyny źródłowe — a potem uruchom ponownie i sprawdź, ile zostało.
  • Komunikat błędu jest naprawdę nieprzejrzysty. Segfaulty i generyczne „internal server error” nie niosą żadnej specyfikacji. Przełącz się z podejścia sterowanego błędami na sterowane hipotezami: dodaj logowanie, odtwórz problem, zawężaj przez eliminację.
  • Błąd jest w wygenerowanym kodzie. Gdy zepsuty plik to ten, który agent napisał od zera, usunięcie go i wygenerowanie ponownie z bardziej ograniczonego promptu zwykle bije łatanie.

Dokąd pójść dalej z programowaniem sterowanym błędami

Dział zatytułowany „Dokąd pójść dalej z programowaniem sterowanym błędami”