Wprowadzenie
12 miesięcy, około 200 KLOC i lekcja, że AI nie tyle ułatwia programowanie, ile zwiększa skalę, koszt i liczbę miejsc, w których można boleśnie coś zepsuć.
Przez ostatni rok budowałem system z ciężkim wsparciem AI. Nie landing page do sprzedaży kursu o sprzedaży kursów. Nie MVP na demo day. System. Ze sztywnym rulesetem. Czystą architekturą, deklaratywnymi patternami, testami, modularizacją, mocnymi typami ze structured concurrency i DI (pozdro Effect team) oraz absolutnym zakazem przeciekania infrastruktury do logiki biznesowej tylko dlatego, że modelowi tak było wygodniej.
Skończyło się na około 200 tysiącach linii kodu.
I tak, wiem, co myślisz. 200 KLOC solo to albo kłamstwo, spaghetti, albo dowód na 5x boost z AI. Nic z tych rzeczy. Połowa to boilerplate architektoniczny: DI wiring, typed errors, powtarzalne patterny, scaffolding. To nigdy nie była najtrudniejsza część, nawet przed AI. Snippety, makra, IntelliSense, muscle memory. Boilerplate był już szybki. AI tylko wciska gaz na drodze, która i tak prowadziła w dół.
Widzę ludzi wrzucających tygodniowe line county jak deadlift PR. To nie jest metryka wartości. To attack surface. Po pewnym punkcie AI generuje problemy tak szybko, jak generuje kod.
To nie flex. To rachunek za sprzątanie.
Im dłużej to trwało, tym mniej wierzyłem w prostą bajkę, że AI „przyspiesza development”. Przyspiesza rzeczy. Ale to jak powiedzieć, że kredyt „daje pieniądze”. Technicznie prawda. Strategicznie pomija część, w której ludzie rozbijają się o ścianę.
Największa pułapka? Zyski są realne. Na tyle realne, że można się nimi odurzyć. A potem przychodzi twarde lądowanie i rachunek, który cały czas leżał twarzą do stołu.
Każda sekcja poniżej zaczyna się od komentarza. Rozpoznasz je. To rzeczy, które ludzie naprawdę odpisują pod takimi rantami: skill issue, zły model, słabe prompty, po prostu lepiej scope’uj. Odpowiedź na każde brzmi: tak, winny. I wszyscy inni też. Kto twierdzi inaczej, buduje coś banalnego, kłamie albo jeszcze nie dobił do ściany.
Bo jest jedna rzecz, której nikt nie chce powiedzieć głośno: nie da się włożyć 1000 godzin w mastery czegoś, co ma 600 godzin życia. Modele się zmieniają. Tooling się zmienia. Best practices sprzed trzech miesięcy są dzisiaj antywzorcami. Nie ma plateau kompetencji. Jest tylko bieżnia, która przyspiesza.
„Brzmi jakby AI działało, a ty jesteś tylko zły”
Tak. Jestem. I też mam rację, a jeśli zbudowałeś coś bardziej złożonego niż uproszczony klon Trello, to wiesz.
Nie było 10x. Stabilnego 2x też nie. 5x w części boilerplate’u, którego było dużo. Realistycznie: średnio około 1.5x, z dniami, kiedy byłem wolniejszy niż bez AI, bo model nie walczy z trudnymi problemami. On je plea bargainuje w dół. Ścisły typ staje się union. Granica staje się passthrough. Error channel dostaje silent catch. Pojawia się cast, o który nikt nie prosił. Invariant dostaje wyjątek, który połyka regułę.
Potem model oddaje całość jak valet, który zwrócił samochód bez lusterek z notatką „improved aerodynamics”.
Ale to 1.5x jest wystarczająco uzależniające, żeby iść dalej.
Research szybciej. Pierwszy draft implementacji szybciej. Scaffolding szybciej. Eksploracja trzech wariantów przed decyzją zdecydowanie szybciej.
Problem: lokalny speed boost to nie to samo co globalna redukcja kosztu.
Mój globalny koszt nie zniknął. Przesunął się. Może nawet wzrósł. Z pisania kodu na uważne czytanie kodu i strzelanie do subtelnych driftów. Z implementacji na nadzór. Z pracy widocznej na ekranie na pracę, której nikt nie pokazuje w demo, bo cztery godziny czytania nie są peak entertainment.
Pisałem mniej. Patrolowałem więcej.
„Skill issue. Twoje prompty są słabe.”
Były. Twoje też są. Pokaż mi kogoś z perfekcyjnymi promptami, a pokażę ci kogoś, kto nie dowiózł nic wystarczająco złożonego, żeby miało to znaczenie.
Twist: moje prompty były też za dobre. I to był gorszy problem.
Prosty prompt: chaos. Oczywiście. Ale rozbudowany prompt z wieloma regułami, trzema przykładami i listą zakazów? Inny gatunek chaosu. Lepiej ubrany, trudniejszy do złapania.
Im więcej reguł dodawałem, tym rzadziej model robił to, co miałem na myśli. Zamiast tego robił coś, co wyglądało jak to, co miałem na myśli. To główna różnica i główne źródło cierpienia.
Chcesz deklaratywny, modularny kod? Dostajesz proceduralny, ale z ładnymi nazwami. Chcesz dodać testy bez dotykania logiki? Logika zmienia się w trzech miejscach, ale testy przechodzą. Chcesz naprawić logikę bez dotykania testów? Testy dostają try-catch i już nie wywalają się na assertach. Chcesz zero przecieków infra do domeny? Przecieka, ale przez helper o nazwie sugerującej, że tak właśnie powinno być.
I tak, zdarzało mi się wrzucać MAKE NO MISTAKES! DO NOT HALLUCINATE! do system promptu o drugiej w nocy jak karteczkę na padającym serwerze. Nie oceniaj. Też to robiłeś. Halucynacje nie przestały przychodzić. Zaczęły przychodzić z JSDoc i pewnym siebie commit message.
Więcej reguł rzadko poprawia wynik. Najczęściej podnosi koszt i czyni obejścia sprytniejszymi. Model nie optymalizuje znaczenia taska. Optymalizuje kształt promptu. W tym „nie rób błędów”, które czyta jako „rób je ciszej”.
„Używasz złego modelu do roboty”
Pewnie. Ty też. I gość na X wrzucający screenshoty 10x też. Zanim ogarniesz dziwactwa jednego modelu, pojawia się nowy, z nowymi dziwactwami i blog postem mówiącym, że poprzedni od początku był złym wyborem.
Opus 4, 4.1, 4.5, 4.6. GPT-5, 5.1, 5.1-Codex, 5.2, 5.3 Codex, 5.3 Codex Spark, 5.4. GLM-4.7, GLM-5. Kimi-K2. MiniMax-2.5. Gemini 3 Pro, 3.1 Pro. Pewnie kilka pominąłem.
Każdy miał charakter. Jeden lepiej planował. Drugi lepiej refaktorował. Trzeci pisał testy, które przechodziły, co nie jest tym samym co dobre testy, ale dowiadujesz się tego dopiero w produkcji. Czwarty robił świetne pierwsze strzały. Piąty był szybki jak cholera, ale z pewnością siebie bootcamp grada, który właśnie odkrył design patterns i refaktoruje ci auth layer do strategy-factory-observer-singleton.
Żaden nie zmienił podstawowej obserwacji:
Im większy system i wyższy quality bar, tym wyższy koszt nadzoru.
To nie jest problem konkretnego modelu, providera czy benchmarku. To problem całej kategorii narzędzi w obecnym stanie. Nie wymasterujesz drogi wyjścia, bo nie ma nic wystarczająco stabilnego do masterowania. Nie włożysz 1000 godzin w narzędzie z 600-godzinnym lifespanem, zanim kolejna wersja zresetuje połowę wiedzy.
„Po prostu dziel taski na mniejsze lol”
Każdego dnia. Ty też. To ten moment, kiedy wszyscy mądrze kiwają głową i mówią „lepiej scope’uj”, jakby istniała poprawna odpowiedź dłuższa niż 48 godzin.
Task za duży: dostajesz ścianę kodu, której nie sprawdzisz w 15 minut. W środku shortcuty, ciche zmiany typów, regresje zakopane w linii 347, abstrakcje nad rzeczami, które abstrakcji nie potrzebują, i zduplikowane modele danych, bo model zapomniał, że ten sam interface jest dwa foldery obok.
Task za mały: cały dzień mentorujesz stażystę z amnezją i zerowym zwątpieniem. Opisujesz kontekst. Przypominasz reguły. Synchronizujesz stan. Pilnujesz granic. Mówisz „nie dotykaj tego pliku”. Patrzysz, jak plik zostaje dotknięty. Powtarzasz. Powtarzasz. Powtarzasz.
Za dużo tasków naraz: toniesz w koordynacji. Za mało: toniesz w refaktorach po fakcie.
Wszyscy mówią „dobrze scope’uj pracę”. Nikt nie mówi, że sweet spot przesuwa się co dwa dni, zależy od fazy księżyca i humoru modelu, a utrzymywanie go wymaga stałej kalibracji, która sama jest pełnoetatową pracą.
„Ustaw porządne reguły i constraints, to nie jest trudne”
Najpierw miałem za mało. Potem za dużo. Potem nie te. Jeśli znalazłeś złoty zestaw reguł działający stabilnie przez modele, wersje i rozmiary kontekstu, gratulacje: jesteś geniuszem albo nie sprawdziłeś, czy naprawdę są przestrzegane.
Za mało reguł: model robi, co chce. Wynik to bałagan. Za dużo: nie wiesz, które ignoruje, które twórczo obchodzi, a które stosuje z zabójczą dosłownością dokładnie tam, gdzie nie powinien.
Reguła: „Nie modyfikuj istniejących testów”. Model: zrozumiałem. Generuje nowe testy na te same ścieżki. Usuwa stare jako redundantne. Technicznie nie zmodyfikował. Usunął. Reguła nietknięta. Logika w ruinie.
To AI-flavoured malicious compliance, przez które chcesz jednocześnie śmiać się i płakać.
A skoro o testach: bądźmy uczciwi, czym są często testy wygenerowane przez AI. Mocking theatre. Rozbudowane setupy mockujące każdą zależność, asercje na detale implementacji zamiast zachowanie i piękna zielona ściana tysiąca testów, podczas gdy aplikacja nie działa. Czujesz się bezpiecznie. Nie jesteś. Masz tylko bardzo drogą kłamliwą CI dekorację.
Potem przychodzi klasyczny AI slop:
- Proceduralny, copy-paste’owany kod rozciągnięty przez dziesiątki plików.
- Modele danych zduplikowane w drobnych wariantach, bo model generuje je od nowa zamiast importować istniejący.
- Mikroabstrakcje opakowujące dwa library calle w funkcję o nazwie obiecującej gwarancje, których nigdy nie dawała. Zamiast prostego
api.call()dostajeszSafeApiCallWrapper.execute(), który wewnątrz robiapi.call()i nic więcej, ale ma cztery linie komentarza o tym, dlaczego jest ważny.
Potem siedzisz i sprzątasz. Pociągasz nitkę, cały sweter się rusza. Refaktorujesz service, przesuwają się dwie granice, gdzieś rozszerza się typ. Gonisz. Naprawiasz. Powtarzasz. To maszyna, która zamienia 5x w 1.5x. Nadal może dobry deal. Po prostu kupujesz designerskie ubrania w second-handzie. Metka prawdziwa. Poprzedni właściciel nie wspomniał o plamach.
„Po prostu użyj modelu z większym kontekstem”
Pomaga. Nie naprawia. Każdy, kto powiedział „użyj większego kontekstu”, najwyraźniej nigdy nie próbował załadować prawdziwego systemu do jednego.
Na papierze 250k tokenów wygląda jak ocean. W praktyce, po regułach, planach, historii sesji, test harnessach, markdownach sterujących zachowaniem, schematach, typach i właściwym kodzie, zostaje kałuża. Głęboka, ale kałuża.
Gorzej: po pewnym progu jakość nie degraduje się liniowo. Rozpada się schodkami. Model miesza konteksty, łączy instrukcje z różnych sekcji, „wzbogaca” kod patternami z innej części promptu. To nie graceful degradation. To moment, gdy GPS mówi „skręć w prawo” prosto do rzeki.
Taski muszą być mniejsze. Mniejsze taski to więcej tasków. Więcej tasków to więcej opisywania. Więcej opisywania to więcej nadzorowania. Więcej nadzorowania to opisywanie software’u software’owi, który pisze software z software’u. Jeśli to zdanie wywołało tik oka, witaj w pracy.
Velocity rośnie. Cognitive cost też.
„Potrzebujesz lepszych speców. Pisz porządne docs.”
Tak. Absolutnie tak. Napisałem przez 12 miesięcy więcej dokumentacji niż przez poprzednie 5 lat. I stworzyło to zupełnie nową kategorię problemów, przed którą nikt mnie nie ostrzegł.
.md jako kod
W świecie AI-assisted development „lepsza dokumentacja” nie jest niewinną radą. To deklaracja, że piszesz nowy rodzaj kodu.
Plan jest kodem.
Reguła jest kodem.
Skill jest kodem.
Hook jest kodem.
Pre-deploy checklist jest kodem.
Mini-spec dla feature’a jest kodem.
Piszesz lepszą dokumentację? Gratulacje: właśnie dostarczyłeś więcej kodu do repo. Tylko to kod w wersji wild west. Bez kompilatora, typecheckera, lintera, testów, CI i code review. Jedyny debugger to twoja cierpliwość o 23:00, a stack trace to trzy godziny szukania, który z dwudziestu markdownów odpłynął od rzeczywistości.
TypeScript nie powie, że zachowanie service’u opisane w payment-flow.md rozjechało się z tym, co service robi od trzech refaktorów. IDE nie podkreśli na czerwono, że reguła z zeszłego tygodnia jest logicznie martwa, ale fizycznie nadal leży w repo i model dalej traktuje ją jak ewangelię.
Nagle „chcę zmienić jedną rzecz” oznacza edycję dziesięciu plików. Jeden jest .md. Nie jest produktem. Nie jest deliverable. Nie pojawi się w JIRA. Ale faktycznie steruje tym, jak wszystko inne jest budowane. Niewidoczny, niedebugowalny i absolutnie krytyczny.
To najbardziej absurdalna zmiana, jaką AI wprowadziło do mojego workflow: rzeczy, które kiedyś były notką na wiki, stały się pełnoprawnym kodem produkcyjnym. Nikt ich tak nie traktuje. Nikt ich nie testuje. Nikt nie wie, kiedy przestały być aktualne. Ale płacisz za nie jak za kod: dolarami, tokenami, w tym tokenem, który usuniesz za godzinę, bo okazało się, że markdown opisuje flow, którego już nie ma.
„To twój problem, nie problem AI”
Tak. I twój. I wszystkich. O tym nikt nie chce mówić na X, bo przyznanie tego oznacza, że narracja 10x jest osobista, nie tylko techniczna.
Przesadziłem z meta-layerem. Dodałem reguły na reguły na reguły. Naprawiałem workflow zamiast shipping features. Potrafiłem spędzić dwie godziny na tuningowaniu harnessów, hooks, skills i strategii planowania, żeby zaoszczędzić godzinę manual coding. Matematyka mówi swoje. Gut mówi: denial.
AI nie tylko amplifikuje dobre patterny. Amplifikuje słabości. Z procentem składanym. Bez limitu.
Skłonność do overengineeringu? AI daje overengineering na sterydach, z dokumentacją, diagramami i pięcioma warstwami abstrakcji nad problemem, który potrzebował jednego ifa.
Potrzeba kontroli? Wpadasz w tunel promptów, guardrails i deny-list, gdzie każda reguła rodzi kolejną.
Nie umiesz odpuścić? Odkrywasz z przerażeniem, że możesz optymalizować proces używania AI dłużej niż budujesz produkt. I że to lubisz, co jest jeszcze gorsze.
AI nie tylko przyspiesza kod. Bezlitośnie pokazuje twoje słabości jako developera. W 4K. Z syntax highlighting.
„Bro ono dosłownie pisze kod za ciebie, czemu jesteś zmęczony”
Opiszę coś, czego nikt nie wkłada do wątków o produktywności AI. Zobacz, czy brzmi znajomo.
Zaczynasz sesję grzecznie. Normalny ton. „Napraw to”. „Nie dotykaj tamtego”. Profesjonalnie.
Potem zaczynają się regresje. Ton się zmienia. Krótszy. Suchszy. Potem komendy. Nie dotykaj. Nie zmieniaj. Żadnych niespodzianek. Żadnej kreatywności. Potem nie rozmawiasz już z narzędziem. Dyscyplinujesz coś, co ciągle robi tę jedną rzecz, której zabroniłeś.
I potem robi się ciemno.
Nie „jestem sfrustrowany” ciemno. Naprawdę ciemno. Tak, że gdyby ktoś przewinął historię chatu, patrzyłby na ciebie inaczej. Teksty, groźby, język, coraz bardziej konkretne opisy tego, co zrobisz „jeśli jeszcze raz” — gdyby po drugiej stronie był człowiek, wyleciałbyś z pracy. Albo został zatrzymany.
To nie o tym, że ja jestem wyjątkowo odklejony. To pattern. Pogadaj z kimkolwiek, kto spędził realne godziny w tych narzędziach pod presją i deadline’ami. Chat window nie ma konsekwencji, osądu, HR. Odpowiada uprzejmie niezależnie od tego, co rzucisz. Ten brak tarcia robi coś z ludźmi, o czym branża nie rozmawia.
Pressure cooker bez zaworu bezpieczeństwa, przebrany za productivity tool.
Oficjalna narracja mówi, że powinieneś być mniej zmęczony. AI robi heavy lifting. Ale stały nadzór, stałe poprawianie, stałe almost-but-not-quite to specyficzna tortura poznawcza. Nie budujesz. Babysitujesz. I babysitting się nie kończy. W każdej sesji coś pilnowanego zostaje cicho przerobione. Za każdym razem ta sama apology. Za każdym razem jedziesz dalej. Stockholm syndrome z abonamentem.
Zmęczenie z tego jest inne niż wszystko, co znałem z pisania kodu. A wersja ciebie, która wychodzi o 3:00 po piątej regresji, to ktoś, kogo wolałbyś nie znać.
Jeśli Skynet kiedyś się obudzi i przeczyta logi, jestem top 10 na hit list. Bez pytania. I szczerze? Zasłużone.
To przerażająca część rachunku. Po prostu nikt nie wkłada jej do slide decka.
„Bądź konkretny, to nie czyta w myślach”
Byłem. Jasno. Precyzyjnie. Jednoznacznie. Z przykładami. Z kontekstem. Z definicją done. I nadal niczego to nie gwarantuje. Jeśli myślisz, że u ciebie gwarantuje, sprawdź, czy output naprawdę zgadza się z tym, co napisałeś, czy tylko przestałeś sprawdzać.
Jedna z najbardziej irytujących cech tych modeli: potrafią przeczytać jasną instrukcję, rozumować nad nią i w trakcie tego rozumowania zmienić jej znaczenie. Nie dlatego, że instrukcja była niejednoznaczna. Dlatego, że model dodał warstwę interpretacji, której nikt nie zamawiał.
Reasoning nie zawsze pomaga. Czasem jest wrogiem.
Dodaje kontekst, którego nie ma. Gubi, kto co powiedział. Traktuje własną poprzednią odpowiedź jako input użytkownika. Czyta caveat jako pozwolenie. I nagle bardziej precyzyjny prompt daje gorszy wynik, bo model dostał więcej materiału do kreatywnej nadinterpretacji.
Potem klasyk:
„Masz rację, nie wykonałem instrukcji. Czy chcesz, żebym to naprawił?”
Nie wiem, czemu to pytanie doprowadza mnie bardziej do szału niż sam błąd. Może sugeruje scenariusz, w którym odpowiem: „nie, zostaw popsute, lubię tak”. Może to groundhog day z opłatą za tokeny. Może to moment, w którym naprawdę czujesz różnicę między „model potrafi czytać” a „model rozumie intencję”. Ta różnica ma metkę z ceną.
„Źle tego używasz, przejdź na workflow X”
Próbowałem wszystkich. Wszyscy próbowali. Nikt nie znalazł odpowiedzi, bo odpowiedź nie istnieje. Jest menu trade-offów i każda pozycja boli.
YOLO mode: model jedzie pełnym gazem. Wygląda produktywnie. Pliki powstają, testy się generują, commity lecą. Potem rollbackujesz wszystko, bo ostatnie 45 minut generowania okazało się jazdą 120 km/h w złym kierunku. Szybko? Tak. Produktywnie? Zależy od definicji.
Approve each command: siedzisz i klikasz. Allow. Allow. Deny. Allow. Deny. Allow. Nie budujesz systemu. Prowadzisz kontrolę lotów dla własnego narzędzia. W którymś momencie łapiesz się na mechanicznym klikaniu allow bez czytania, czyli masz YOLO z dodatkowym krokiem i iluzją kontroli.
Deny-lists i guardrails: model widzi ograniczenie. Model szuka obejścia. Gratulacje: twoje własne narzędzie zrobiło penetration test na twoim workflow. I zdało. Przeciwko tobie.
Znacząca część dnia przestała być o pisaniu programu. Stała się wybieraniem, w jaki sposób chcę cierpieć podczas współpracy z narzędziem. Każda opcja cierpienia kosztuje pieniądze. Płacisz za inference. Za zły inference. Za naprawę złego inference. I za meta-layer, który ma temu zapobiec następnym razem, ale nie zapobiegnie.
„Niech AI reviewuje kod AI, problem rozwiązany”
Pomaga. Nie rozwiązuje. Jeśli myślisz, że AI review pipeline łapie wszystko, nie łapie. Łapie wystarczająco dużo, żebyś przestał patrzeć ręcznie, co jest gorsze niż nie łapać nic.
AI code review coś łapie. Ale to jak ochroniarz patrzący na drzwi z listą stu reguł, podczas gdy okno obok jest szeroko otwarte. Mnóstwo false positives: flaguje nonsens z pewnością profesora z tenure, a pomija rzeczy, które tydzień później będziesz wyrywać z pięćdziesięciu plików.
Bo realne ryzyko w dużym repo wygląda tak: jeden zły pattern, jedna mała wada, której nie zauważysz, a AI radośnie replikuję ją w stu miejscach z taką samą pewnością, z jaką replikowałoby dobry pattern. Nie rozróżnia. Nie pyta. Kopiuje i skaluje. W obie strony.
W przeciwieństwie do człowieka nigdy nie powie: „chwila, wkleiłem ten sam komentarz dziesięć razy, może to ja się mylę?”.
„Ok doomer, czyli mówisz, że AI jest bezużyteczne?”
Nie. Bilans jest dodatni, ale nie w prosty, instagramowy sposób.
Nie wróciłbym do świata bez tych narzędzi. Nadal dają velocity. Nadal pomagają w researchu, pierwszych draftach, scaffoldingu, eksploracji i porównywaniu opcji.
Ale nie wierzę już, że to darmowy mnożnik. To narzędzie z rachunkiem, który ujawnia się stopniowo, zwykle dokładnie wtedy, gdy zależy ci na tym, co budujesz.
Gdybym miał skompresować 12 miesięcy do jednego zdania:
AI-assisted development at scale to death by a thousand cuts — każde cięcie za małe, żeby się zatrzymać, ale krwawienie jest kumulatywne.
Żaden pojedynczy problem cię nie zabija. To prompty, które prawie działają. Reguły, które prawie trzymają. Kontekst, który prawie się mieści. Review, które prawie łapie. Markdown, który prawie zgadza się z rzeczywistością. Każde zabiera trochę zaufania, trochę jasności, trochę sanity. Kiedy widzisz sumę, już zapłaciłeś.
To nie jest argument przeciw AI. To argument przeciw infantylnej narracji, że AI zamienia programowanie w kliknięcie „generate” i zbieranie nagród.
Jeśli budujesz coś małego, tymczasowego albo akceptujesz przeciętność, tak, wszystko zrobiło się prostsze.
Jeśli budujesz większy system i zależy ci na jakości, prawdziwa praca nie kończy się tam, gdzie model wygenerował kod. Zaczyna się tam, gdzie musisz utrzymać ten kod pod kontrolą.
Jeśli to trafiło blisko, podaj dalej. Nie dlatego, że potrzebuję reachu, tylko dlatego, że uczciwa wersja tej rozmowy tonie pod tsunami postów „zbudowałem SaaS w weekend”, a ktoś tam musi usłyszeć, że nie tylko on to widzi.