Jak wykorzystać AI do automatyzacji zadań programisty w codziennej pracy

0
7
Rate this post

Nawigacja po artykule:

Od hype’u do narzędzia: po co programiście własny „stack AI”

AI jako realne narzędzie pracy, a nie gadżet

AI w pracy programisty przestaje być ciekawostką. Dobrze skonfigurowany „stack AI” potrafi realnie skrócić czas implementacji funkcji, przyspieszyć debugowanie i odciążyć przy zadaniach typu copy&paste. Różnica między gadżetem a narzędziem jest prosta: gadżet bawi przez tydzień, narzędzie po miesiącu użycia daje wyczuwalne oszczędności czasu i energii.

Dla programisty „stack AI” to zestaw konkretnych elementów: model językowy (LLM) używany do rozmów technicznych, asystent zintegrowany z IDE, kilka skryptów lub workflowów CI/CD wspieranych przez AI oraz własne procedury korzystania z tych zasobów. Chodzi o to, by AI było pod ręką dokładnie tam, gdzie najczęściej pojawia się tarcie: przy pisaniu boilerplate’u, generowaniu testów, analizie błędów i tworzeniu dokumentacji.

W praktyce AI zmienia sposób myślenia o zadaniach. Zamiast wykonywać ręcznie każdą powtarzalną czynność, programista zaczyna pytać: „czy da się to opisać na tyle precyzyjnie, żeby AI zrobiło 70% roboty, a ja tylko dopracuję resztę?”. Kto raz wejdzie w ten tryb, bardzo szybko zaczyna budować własny, dopasowany do siebie „stack AI” – nawet jeśli początkowo korzysta tylko z jednego modelu w przeglądarce.

Co nadaje się do automatyzacji w pracy programisty

Nie każde zadanie programisty da się sensownie zautomatyzować. Dobrym filtrem są trzy proste kryteria:

  • Powtarzalność – robisz to samo (lub bardzo podobne) kilka razy w tygodniu.
  • Przewidywalność – wejście i wyjście da się opisać jasno, bez odwoływania się do „przeczucia” czy intuicji domenowej.
  • Niski „creative load” – zadanie nie wymaga głębokiego projektowania architektury czy rozwiązywania nietypowych edge-case’ów.

Automatyzacji dobrze poddają się między innymi:

tworzenie powtarzalnych modułów (np. kolejne CRUD-y w tym samym stylu), generowanie testów jednostkowych według zadanego schematu, pisanie prostych skryptów migracyjnych, translacja kodu między wersjami frameworków, generowanie szablonów endpointów API, składanie dokumentacji z komentarzy w kodzie.

Dużo trudniej zautomatyzować zadania związane z kluczową logiką biznesową, projektowaniem architektury systemu czy podejmowaniem decyzji produktowych. Tutaj AI może pełnić rolę pomocnika (np. proponować warianty architektury lub wzorce projektowe), ale ostatnie słowo zostaje po stronie człowieka.

Typy narzędzi AI przydatnych dla developera

Przy budowaniu własnego „stacku AI” warto odróżnić trzy główne klasy narzędzi:

  • Modele językowe (LLM) w interfejsie czatowym – ogólne modele, z którymi rozmawiasz jak z technicznym kolegą. Nadają się do projektowania rozwiązań, wyjaśniania błędów, dyskusji o architekturze, refactoringu konceptualnym.
  • Asystenci zintegrowani z IDE – rozszerzenia do VS Code, JetBrains czy Vim/Neovim, które podpowiadają kod w czasie pisania, generują całe bloki implementacji, sugerują testy i refaktoryzacje.
  • Dedykowane narzędzia developerskie – rozwiązania typu Copilot, CodeWhisperer, Tabnine, ale też narzędzia do generowania testów, opisu pull requestów, analizy diffów czy skanowania bezpieczeństwa z użyciem AI.

Każda z tych grup rozwiązuje inny problem. Model czatowy świetnie rozłoży na czynniki pierwsze trudny bug, ale nie podpowie ci w czasie rzeczywistym kodu w edytorze. Z kolei asystent IDE będzie super przy boilerplate, lecz gorzej poradzi sobie z analizą kilkusetlinijkowego stack trace’a bez dodatkowego kontekstu.

Realistyczne oczekiwania wobec AI w kodowaniu

AI nie jest junior developerem, który „jakoś to ogarnie”, tylko probabilistycznym modelem tekstowym. Świetnie radzi sobie w obszarach, gdzie są tysiące podobnych przykładów w danych treningowych, i dużo gorzej tam, gdzie projekt jest naprawdę unikalny lub wymaga głębokiego zrozumienia domeny biznesowej.

W czym AI faktycznie pomaga:

  • przyspiesza pisanie powtarzalnego kodu (boilerplate, integracje z dobrze znanymi bibliotekami),
  • wskazuje typowe pułapki (np. błędy z czasem, nullem, konkurencją, transakcjami),
  • porządkuje myślenie – wymusza jasne opisanie problemu, co często samo w sobie prowadzi do rozwiązania,
  • generuje wstępne wersje testów, migracji, dokumentacji, które potem można ulepszać.

Co nadal robi człowiek:

  • decyduje o architekturze systemu i głównych zależnościach,
  • ocenia jakość proponowanych rozwiązań i ich wpływ na cały system,
  • ponosi odpowiedzialność za bezpieczeństwo, zgodność z regulacjami i wymaganiami biznesu,
  • utrzymuje standardy zespołu – styl, konwencje, zasady code review.
Ekran komputera z kodem i panelem akcji AI dla programisty
Źródło: Pexels | Autor: Daniil Komov

Mapowanie własnego dnia pracy: gdzie AI ma największy zwrot z inwestycji

Rozpisanie dnia programisty na mikro-zadania

Przed wprowadzeniem automatyzacji warto zmapować swój typowy dzień pracy. Zamiast myśleć „piszę feature X”, lepiej rozbić go na mikro-zadania:

  • czytanie zgłoszeń w Jirze / GitHub Issues / YouTrack,
  • analiza wymagań biznesowych (specyfikacje, komentarze product ownera),
  • projektowanie rozwiązania (diagramy, szkice API, decyzje o strukturze danych),
  • implementacja kodu aplikacyjnego,
  • pisanie testów (unit, integration, e2e),
  • debugowanie i analiza logów,
  • code review w obie strony,
  • tworzenie dokumentacji i komentarzy,
  • komunikacja: komentarze do PR, odpowiedzi na pytania zespołu, opisy decyzji.

Dopiero na takim poziomie widać, gdzie automatyzacja zadań programisty ma największy sens. Często okazuje się, że najwięcej „tarcia” nie ma przy samym pisaniu kodu, lecz przy testach, dokumentacji albo w żmudnym przepisywaniu podobnych fragmentów logiki do kolejnych modułów.

Tygodniowe ćwiczenie: identyfikacja kandydatów do automatyzacji

Skuteczne wprowadzenie AI w codzienną pracę developera dobrze zacząć od prostego eksperymentu. Przez jeden tydzień prowadź krótkie notatki: za każdym razem, kiedy czujesz irytację lub powtarzalność zadania, dopisz je do listy. Nie trzeba szczegółów – wystarczy kategoria i szacunkowy czas, np. „pisanie testów dla serwisu X – 2h, czysta powtarzalność” czy „aktualizacja dokumentacji API – przepisywanie schematów – 45 min”.

Po kilku dniach lista zaczyna się powtarzać. Z tych notatek możesz zbudować bazę kandydatów do automatyzacji, posortowaną według potencjalnego zwrotu z inwestycji (dużo czasu + wysoka powtarzalność = priorytet). W kolejnym kroku do każdego zadania dopisz możliwe użycie AI: generowanie kodu, generowanie testów, tworzenie szablonów, automatyczne podsumowania.

Uwaga: nawet jeśli część pozycji wydaje się „zbyt mała”, by je automatyzować, po zsumowaniu wszystkich okazuje się, że tygodniowo oszczędzasz kilka godzin. Dla zespołu to już realna różnica.

AI jako „lupa diagnostyczna” dla własnej pracy

Ciekawym meta-podejściem do automatyzacji jest użycie AI… do analizy własnych zadań. Działa to tak: na koniec dnia wrzucasz do modelu krótkie podsumowanie wykonanych czynności (bez wrażliwych danych) i prosisz o sugestie, gdzie AI mogłoby przejąć część pracy.

Przykładowy prompt (w dużym skrócie):

„Jestem backend developerem w projekcie X. Dzisiaj robiłem: 1) analizę zgłoszeń błędów, 2) dopisywanie testów jednostkowych dla istniejącego serwisu, 3) poprawki w zapytaniach SQL, 4) pisanie komentarzy w PR. Które z tych zadań da się zautomatyzować przy pomocy modelu językowego lub asystenta w IDE? Proszę o konkretne propozycje workflowów.”

Model zazwyczaj wskaże kilka „oczywistości”, ale bywa, że podpowie mniej oczywiste rozwiązania, np. półautomatyczne generowanie opisów PR na podstawie diffów, czy generowanie zapytań SQL z opisu w naturalnym języku.

Przykład: refaktoryzacja starego modułu krok po kroku

Refaktoryzacja legacy kodu to dobry przykład zadania, gdzie AI może znacząco przyspieszyć pracę, o ile dobrze je „wpuści się” do procesu. Zamiast wrzucać cały moduł do modelu i proszić: „zrób refactoring”, lepiej podejść iteracyjnie:

  1. Analiza struktury – ręcznie identyfikujesz główne klasy, funkcje, zależności. Do AI wrzucasz wycinek i prosisz: „wyjaśnij, co robi ta klasa, jakie ma odpowiedzialności i jakie widzisz problemy z jej projektowaniem”.
  2. Propozycja architektury – na podstawie tego opisu prosisz model o zaproponowanie nowego podziału modułu na mniejsze komponenty lub warstwy (np. rozdzielenie logiki domenowej od warstwy infrastruktury).
  3. Kontrakty i interfejsy – definiujesz, jakie interfejsy mają mieć nowe klasy / serwisy, i prosisz AI o szkic kodu z minimalną logiką, ale z pełnym API.
  4. Migracja krok po kroku – prosisz model o wygenerowanie planu migracji: które funkcje przenosić w jakiej kolejności, jakie testy dopisać po drodze, jak utrzymać kompatybilność.
  5. Wsparcie przy testach – dla każdej migrowanej części prosisz AI o wygenerowanie zestawu testów, w tym przypadków brzegowych, na podstawie opisu zachowania.

Takie podejście łączy ludzką kontrolę nad architekturą z automatyzacją zadań niskopoziomowych. AI staje się partnerem przy pisaniu kodu i testów, ale nie przejmuje sterów nad całym procesem refaktoryzacji.

Programista w okularach pracuje na laptopie z otwartym narzędziem AI
Źródło: Pexels | Autor: Matheus Bertelli

Jak rozmawiać z modelem: praktyczny prompt engineering dla programistów

Schemat skutecznego promptu technicznego

Prompt engineering dla programistów to przede wszystkim precyzja. Dobry prompt ma kilka stałych elementów:

  • Rola – określasz, kim ma być model: „doświadczony backend developer w Node.js”, „ekspert od baz danych PostgreSQL”, „senior DevOps z doświadczeniem w Kubernetes”.
  • Kontekst techniczny – tech stack, wersje bibliotek, system operacyjny, kluczowe ograniczenia (np. „musimy zostać przy Node 16”, „nie mamy dostępu do zewnętrznego storage’u”).
  • Cel – czy chodzi o diagnozę błędu, wygenerowanie kodu, zaprojektowanie API, czy rewizję istniejącego rozwiązania.
  • Styl odpowiedzi – np. „krótko i konkretnie”, „wypunktuj kroki”, „pokaż minimalny działający przykład”.
  • Format wyjścia – żądanie konkretnego formatu: snippet kodu, blok markdown, JSON, struktura testów.

Przykład:

„Jesteś doświadczonym backend developerem w Node.js i NestJS. Używamy PostgreSQL i TypeORM. Celem jest zaprojektowanie endpointu do wyszukiwania użytkowników z paginacją i filtrowaniem po roli. Odpowiedź podaj w postaci: 1) definicja DTO, 2) sygnatura metody w serwisie, 3) przykład zapytania TypeORM. Bez pełnej aplikacji, tylko szkice.”

Takie polecenie zazwyczaj daje dużo lepszy efekt niż ogólne „napisz endpoint do wyszukiwania użytkowników”. Model ma jasny kontekst i wie, jaką odpowiedź ustrukturyzować.

Kiedy wklejać kod, a kiedy tylko opisywać problem

Generowanie kodu przez AI wymaga wyczucia, czy faktycznie trzeba wysyłać duży fragment źródeł, czy wystarczy jasny opis. Kilka zasad praktycznych:

  • Opis wystarczy, gdy: projektujesz nowe API, pytasz o wzorce projektowe, szukasz typowych rozwiązań dla znanych problemów (np. rate limiting, retry, cache), prosisz o przykład użycia biblioteki.
  • Wklejasz kod, gdy: debugujesz konkretny fragment, prosisz o refactoring istniejącej funkcji, analizujesz złożoną zależność, potrzebujesz wytłumaczenia „co tu się dzieje”.

Cykle pytań i doprecyzowań zamiast jednego „magicznego” promptu

Przy zadaniach technicznych lepiej działa dialog niż jednorazowy, ogromny prompt. Zamiast od razu prosić o „kompletną implementację modułu płatności”, rozbij interakcję na krótsze kroki i iteracje.

Przykładowy workflow:

  1. Ustalenie kierunku – najpierw pytasz o podejście architektoniczne: „jakie masz opcje, jakie są plusy/minusy”.
  2. Wejście w szczegóły – dopiero po wyborze kierunku prosisz o szkic API, strukturę modułów, kontrakty.
  3. Iteracyjne poprawki – na koniec wrzucasz fragmenty wygenerowanego kodu i prosisz o optymalizację lub dostosowanie do konkretnych ograniczeń projektu.

Takie podejście pozwala wychwycić nieporozumienia wcześniej. Jeśli już na etapie high-level designu coś się rozjedzie, nie marnujesz czasu na poprawianie dużej ilości wygenerowanego kodu.

Do kompletu polecam jeszcze: AI w narzędziach developerskich: przegląd najciekawszych asystentów kodu na rynku — znajdziesz tam dodatkowe wskazówki.

Podawanie ograniczeń i anty-wzorów

Modele lubią sięgać po „typowe” rozwiązania (np. użycie najpopularniejszej biblioteki), które nie zawsze pasują do projektu. Dobrze jest w promptach jasno zaznaczać nie tylko to, co jest dozwolone, ale też to, czego chcesz uniknąć.

Przykładowe ograniczenia, które opłaca się dopisywać:

  • „nie używaj ORM, tylko czyste SQL” – gdy projekt ma już ustaloną konwencję,
  • „bez zewnętrznych zależności poza standardową biblioteką” – przy kodzie osadzonym (embedded) lub w lambda functions,
  • „nie używaj reflection / dynamicznego importu” – gdy zależy ci na statycznej analizie i prostym bundlowaniu,
  • „zachowaj kompatybilność z Python 3.9” – jeśli stack jest „zamrożony” w starszej wersji.

Można też wprost wskazać anty-wzorce, których chcesz uniknąć: „nie duplikuj logiki biznesowej, preferuj wydzielenie helpera”, „unikaj static state, preferuj DI (dependency injection)”. Model zaczyna wtedy lepiej trafiać w styl zespołu.

„Show, don’t tell”: przykład dobrego i słabego promptu

Dwa prompt’y o podobnym celu, a zupełnie różny efekt.

Słaby:

Napisz serwis w NestJS do obsługi płatności kartą.

Mocniejszy:

Jesteś doświadczonym backend developerem w NestJS.
Kontekst:
- moduł Payments w aplikacji monolitycznej,
- komunikacja z zewnętrznym providerem kart (REST API),
- bez ORM, używamy czystego SQL przez pg-promise,
- język: TypeScript, NestJS 9.

Cel:
Zaproponuj strukturę modułu płatności:
1) pliki i ich rola,
2) interfejs serwisu PaymentsService,
3) przykładowy fragment implementacji metody createPayment, bez szczegółów walidacji.

Unikaj:
- logiki biznesowej w kontrolerach,
- statycznych singletonów, wszystko przez DI.

W drugim przypadku model nie tylko wypluwa kod, ale też strukturę i uzasadnienie. Ty zachowujesz kontrolę nad architekturą, AI dostarcza „klocki”.

Walidacja odpowiedzi: checklista dla programisty

Odpowiedzi modeli trzeba traktować jak kod z zewnętrznego repo. Krótka checklista pomaga w codziennej pracy:

  • Kompatybilność – czy używane API i wersje bibliotek istnieją i pasują do twojego stacku?
  • Bezpieczeństwo – czy wejścia są walidowane, czy nie ma jawnego logowania wrażliwych danych, czy błędy nie wyciekają na zewnątrz?
  • Testowalność – czy kod da się sensownie przetestować (brak twardych zależności, możliwość wstrzyknięcia mocków)?
  • Czytelność – czy za pół roku ktoś z zespołu zrozumie tę funkcję bez wertowania dokumentacji modelu?

Jeśli któryś punkt wypada słabo, użyj kolejnego promptu w stylu „przerób ten kod, żeby…”, zamiast poprawiać wszystko ręcznie.

Programista w słuchawkach koduje przy biurku z dwoma monitorami
Źródło: Pexels | Autor: hitesh choudhary

Generowanie kodu: kiedy delegować, a kiedy pisać samodzielnie

Obszary, gdzie AI ma największy sens przy generowaniu kodu

Nie każdy typ kodu daje taki sam zwrot z delegowania go modelowi. Są obszary, gdzie AI jest szczególnie skuteczne:

  • Boilerplate i „klej” – konstrukcje powtarzalne: definicje DTO, mappery, rejestracja zależności w kontenerze DI, proste adaptery do zewnętrznych API.
  • Interfejsy i szkielety – definicje interfejsów, abstrakcji, klas bazowych, do których dopiero dopisujesz logikę domenową.
  • Kod pomocniczy – funkcje narzędziowe (np. parsowanie dat, walidacja prostych struktur, generowanie slugów).
  • Prototypy – szybkie „proof of concept” dla biblioteki czy nowego podejścia (np. demo integracji z S3, WebSocket, feature flagami).

W tych przypadkach ręczne pisanie bywa żmudne. Model odtwarza znane wzorce szybciej, a ty skupiasz się na miejscach, gdzie potrzebna jest domenowa wiedza.

Gdzie generowanie kodu kończy się kłopotami

Są też strefy, gdzie ślepe poleganie na generowaniu kodu potrafi solidnie „ugryźć” później:

  • Kluczowa logika domenowa – reguły biznesowe, które odróżniają twoją aplikację od setek innych. Tu najważniejsze są niuanse i scenariusze brzegowe, których model nie zna.
  • Krytyczne ścieżki bezpieczeństwa – autoryzacja, kryptografia, obsługa uprawnień, walidacja danych wejściowych.
  • Wysoko wydajnościowe fragmenty – np. pętle w gorących ścieżkach, fragmenty przetwarzające duże wolumeny danych, mechanizmy cache’owania specyficzne dla danego systemu.
  • Kod złożony z wielu nieliniowych decyzji – duże maszyny stanów, skomplikowane workflowy, rozproszona koordynacja (sagi, orkiestracje).

Modele są dobre w syntaksie i „typowych” rozwiązaniach. Tam, gdzie musisz wziąć pod uwagę lokalne uwarunkowania biznesowe, przepisy, procesy w firmie – odpowiedzialność za projekt i implementację pozostaje po twojej stronie.

Strategia „najpierw ręcznie, potem automatyzuj”

Przy bardziej złożonych elementach systemu często najlepiej zadziała podejście dwuetapowe:

  1. Ręczna pierwsza implementacja – tworzysz minimalną, ale świadomie zaprojektowaną wersję (MVP) funkcji lub modułu.
  2. Automatyczne rozszerzanie – używasz AI do:
    • dodania kolejnych endpointów na tym samym wzorcu,
    • rozszerzenia pokrycia testami według już przyjętej struktury,
    • wygenerowania powtarzalnych adapterów do innych kontekstów.

W ten sposób model „uczy się” na twoim stylu i strukturze kodu. Masz bazę, która odzwierciedla wymagania biznesowe i architekturę, a AI tylko ją powiela i skaluje.

Przykład: CRUD vs. logika domenowa

Przy prostych encjach (np. „Tag”, „Kategoria”, „Adres korespondencyjny”) można bez większych obaw wygenerować pełny CRUD: modele, repozytoria, kontrolery, DTO i testy szczęśliwych ścieżek. Model od razu wygeneruje wzorce, które już zna z setek podobnych przykładów.

Gdy jednak pracujesz nad modułem „Rozliczenia” czy „Reguły cenowe”, delegowanie pełnego kodu do AI może skończyć się sytuacją, gdzie ładnie wygląda tylko pierwsza iteracja. Potem dochodzą wyjątki biznesowe, lokalne regulacje, specyficzne edge-case’y – i nagle łatwiej jest przepisać moduł ręcznie, niż łatać wygenerowaną bazę. Rozsądniej jest w takim wypadku poprosić AI o:

  • propozycję struktur danych,
  • zestaw testów dla 2–3 przykładowych reguł,
  • pomoc w implementacji pojedynczych funkcji (np. kalkulacji), ale na podstawie twojej precyzyjnej specyfikacji.

Kontrolowanie „poziomu szczegółowości” generowanego kodu

Modele czasem tworzą zbyt skomplikowane rozwiązania dla prostych problemów (overengineering). Można temu zapobiec, prosząc wprost o określony poziom szczegółowości:

  • „pokaż tylko minimalny działający przykład, bez obsługi błędów i edge-case’ów”,
  • „zaproponuj wyłącznie sygnatury metod, bez implementacji”,
  • „podaj jedną, najprostszą działającą wersję, bez wzorców typu Factory/Strategy”.

Potem krok po kroku dokładasz kolejne aspekty: obsługę błędów, retry, logowanie, integrację z resztą systemu. W ten sposób kontrolujesz złożoność, zamiast dostawać „enterprise framework” tam, gdzie wystarczyłaby prosta funkcja.

Dlatego rozsądniej traktować AI jak bardzo szybką, ale czasem „zmyślającą” bibliotekę pomocniczą niż jak samodzielnego programistę. Ten sposób myślenia jest spójny z trendami w ekosystemie Informatyka, Nowe technologie, AI, gdzie podkreśla się rolę człowieka jako architekta i weryfikatora rozwiązań generowanych przez modele.

AI jako gumowa kaczka do debugowania i analizy istniejącego kodu

Technika „głośnego myślenia” z modelem

Gumowa kaczka (rubber duck debugging) polega na tłumaczeniu komuś (lub czemuś) krok po kroku, co robi twój kod. Modele świetnie się do tego nadają, o ile dobrze przygotujesz materiał.

Prosty schemat:

  1. Wklejasz fragment kodu (lub kilka powiązanych funkcji).
  2. Opisujesz własnymi słowami, co według ciebie powinno się dziać.
  3. Pytasz: „Czy ten kod faktycznie to robi? Jeśli nie, pokaż różnice krok po kroku”.

Sam akt precyzyjnego opisania oczekiwanego zachowania często wystarcza, żeby zauważyć błąd jeszcze przed przeczytaniem odpowiedzi. Model jest tu partnerem, który wskazuje rozjazdy między deklaracjami a implementacją.

Debugowanie: jakie dane przekazywać, żeby miało sens

Przy debugowaniu kluczowy jest kontekst. Zbyt mało informacji – model zgaduje. Za dużo – gubisz się w ścianie tekstu. Dobry pakiet diagnostyczny zawiera:

  • Minimalny fragment kodu powiązany z problemem (funkcja, metoda, fragment konfiguracji),
  • Opis błędu – treść stack trace, komunikaty z logów, różnica między oczekiwanym a faktycznym wynikiem,
  • Warunki brzegowe – specyficzne dane wejściowe, przy których błąd się pojawia,
  • Środowisko – lokal/dev/prod, wersje runtime (Node, Python, JVM), używane frameworki.

Przykładowy prompt:

Jestem backend developerem w Spring Boot 3.

Kontekst:
- Endpoint REST do tworzenia zamówienia,
- Baza: PostgreSQL 14, używamy Spring Data JPA.

Problem:
Przy próbie zapisania nowego zamówienia z więcej niż 50 pozycjami
dostajemy błąd "org.hibernate.TransactionException: Transaction marked as rollbackOnly".

Poniżej:
1) metoda kontrolera,
2) metoda serwisu,
3) stack trace błędu.

Pytanie:
- co może powodować ten błąd w takiej konfiguracji,
- jakie 3–4 hipotezy sprawdzić w pierwszej kolejności?

Zamiast prosić o „naprawienie kodu”, pobudzasz model do generowania hipotez diagnostycznych. Szybciej przechodzisz od chaosu do listy konkretnych rzeczy do sprawdzenia.

Analiza cudzego (lub legacy) kodu

Przy pracy z obcym modułem wiele czasu schodzi na zrozumienie, jak w ogóle „płynie” tam logika. Modele mogą zrobić pierwsze przejście za ciebie, o ile poprosisz je o odpowiedni typ analizy.

Kilka przykładowych „trybów” analizy, które się sprawdzają:

  • Mapa przepływu – „zrób listę kroków wykonywanych od wejścia do tej funkcji do miejsca X, w formie punktów”.
  • Wydzielenie odpowiedzialności – „jakie odpowiedzialności pełni ta klasa? Które z nich można wydzielić, żeby zmniejszyć złożoność?”.
  • Identyfikacja zależności – „z jakimi innymi klasami / modułami wchodzi w interakcje ten fragment kodu? Co się stanie, jeśli zmienimy podpis tej metody?”.

Szerszą klasę rozbijasz na mniejsze części: najpierw jedna metoda, potem druga, potem model proszony jest o syntezę „jak to działa razem”. Zamiast jednego dużego zrzutu, dostajesz serię czytelnych notatek.

Wykrywanie subtelnych bugów i edge-case’ów

Modele radzą sobie z wychwytywaniem typowych klas błędów: brak null-checków, niespójne użycie typów, wyścigi danych, brak obsługi wyjątku. Gdy poprosisz o „poszukaj potencjalnych edge-case’ów w tym kodzie”, często wskażą:

  • co się stanie, gdy lista będzie pusta lub bardzo duża,
  • jak kod zareaguje na timeout z zewnętrznego serwisu,
  • czy obsługa wyjątków nie zasłania kluczowych błędów,
  • jakie skutki ma brak transakcji przy kilku operacjach na bazie.

Od „podpowiedz mi” do wspólnego debugowania krok po kroku

Modele można wciągnąć głębiej w sam proces debugowania, traktując je jak juniora z dostępem tylko do tego, co mu pokażesz. Chodzi o prowadzenie analizy w iteracjach, zamiast jednego, przeładowanego promptu.

Przykładowy schemat sesji:

  1. Na start dajesz minimalny kod + błąd i prosisz o hipotezy.
  2. Z hipotez wybierasz 1–2 najbardziej sensowne i odpalasz je lokalnie.
  3. Wynik (logi, nowe wyjątki, zachowanie) wrzucasz z powrotem do modelu z komentarzem: „sprawdziłem X, wygląda tak i tak, co dalej?”

Takie „ping-pong” potrafi przyspieszyć dojście do sedna problemu, bo model nie musi od razu wymyślać idealnego rozwiązania. Możesz go też poprosić o wygenerowanie konkretnych snippetów diagnostycznych:

  • dodatkowych logów w kluczowych miejscach (z sensownym formatem),
  • prostego skryptu do odtworzenia problemu (np. curl, Postman, k6),
  • małego testu jednostkowego, który izoluje podejrzany przypadek.

To szczególnie pomaga przy bugach „znikających” na lokalnym środowisku – zamiast zgadywać, możesz kazać AI ułożyć plan systematycznego zawężania obszaru poszukiwań.

Przekształcanie sesji debugowania w dokumentację techniczną

Dość często po rozwiązaniu problemu brakuje czasu i energii, żeby spisać notatkę „jak to działa i czemu się zepsuło”. Tutaj model może odwalić lwią część pracy. Wystarczy, że w trakcie lub po zakończonej sesji debugowania wrzucisz mu:

W tym miejscu przyda się jeszcze jeden praktyczny punkt odniesienia: NestJS w praktyce: jak uporządkować architekturę aplikacji Node.js.

  • kluczowe fragmenty stack trace,
  • wycinki z logów przed i po poprawce,
  • diff zmian (np. git diff z jednego commita).

Następnie prosisz o stworzenie krótkiej notatki w wybranym formacie, np.:

Na podstawie poniższych informacji:
- stack trace
- opis problemu z Jiry
- diff z commita

Przygotuj:
- zwięzły opis przyczyny błędu,
- jak działa poprawione rozwiązanie,
- jedną sekcję "Jak powtórnie zdiagnozować podobny problem".

Użyj języka technicznego, ale zrozumiałego dla mid developera Java/Spring.

Efekt możesz wkleić jako komentarz do taska, do Confluence’a albo do pliku docs/known-issues.md. Z czasem tworzy się użyteczna baza wiedzy, zamiast chaotycznego wątku na Slacku.

Refaktoryzacja z asekuracją AI

Legacy kod zazwyczaj odstrasza rozmiarem i ilością zależności. Modele przydają się tu jako „drugi mózg” przy planowaniu refaktoryzacji krok po kroku, bez dużych, ryzykownych skoków.

Przy większym module możesz zastosować prosty workflow:

  1. Wrzucasz 1–2 kluczowe klasy z opisem kontekstu: „moduł X odpowiada za …, ograniczenia są takie: …”.
  2. Prosisz o identyfikację naturalnych granic (bounded contexts, odpowiedzialności), np.: „wypisz logiczne fragmenty odpowiedzialności, które można byłoby rozdzielić na mniejsze klasy / serwisy”.
  3. Wspólnie z modelem wymyślacie plan refaktoryzacji w małych krokach:
    • co można wydzielić bez zmiany API,
    • jak dodać testy zabezpieczające obecne zachowanie,
    • jak wprowadzić nową strukturę, nie psując istniejących integracji.

Tip: zamiast prosić o „przepisanie klasy na nowo”, lepiej poprosić o przejściowy etap, np.: „dodaj nową klasę, która przejmie odpowiedzialność X, a starą zostaw jako cienką fasadę delegującą”. Model chętnie generuje „rewolucje”; ty potrzebujesz ewolucji, którą da się bezpiecznie wdrożyć.

Porównywanie dwóch wersji implementacji

Podczas refaktoryzacji naturalnie powstają dwie wersje tej samej logiki: stara i nowa. Zamiast ręcznie skakać po diffie, możesz poprosić model o porównanie semantyczne (co się realnie zmieniło w zachowaniu, a nie tylko w linijkach kodu).

Praktyczny wzorzec promptu:

Poniżej dwie wersje tej samej funkcji:
1) STARA
2) NOWA

Zadanie:
- wypisz różnice w logice biznesowej (nie obchodzi mnie formatowanie, nazwy zmiennych),
- wskaż sytuacje, w których NOWA wersja zadziała inaczej niż STARA,
- zaproponuj 3–5 testów, które pokryją te różnice.

Na tej podstawie możesz dostawić testy regresyjne dokładnie tam, gdzie istnieje ryzyko, że „przy okazji” zmieniłeś zachowanie aplikacji. To szczególnie pomaga przy skomplikowanych regułach biznesowych, gdzie manualne ogarnięcie wszystkich ścieżek wymaga dużo czasu.

AI jako strażnik stylu i dobrych praktyk

Poza „ratowaniem z opałów” modele świetnie nadają się do codziennego pilnowania jakości: spójnego stylu, sensownej struktury testów, rozsądnego podziału odpowiedzialności. Nie chodzi o zastępowanie code review, ale o darmowego, niestrudzonego recenzenta pierwszej linii.

Kilka typów pytań, które dobrze działają w tym kontekście:

  • „Jakie potencjalne problemy architektoniczne widzisz w tej klasie/folderze?”
  • „Czy ten kod łamie jakieś zasady SOLID / Clean Code? Wypisz konkretne miejsca i alternatywne podejścia.”
  • „Jakie konwencje nazewnictwa są niespójne w tym module?”

To działa szczególnie dobrze w młodszych zespołach, gdzie nie ma jeszcze silnej kultury review. Model, jeśli odpowiednio go poprowadzisz („bądź surowym reviewerem, skup się na potencjalnych problemach, nie na pochwałach”), potrafi wychwycić sporo „kodowego bałaganu” zanim trafi on do głównej gałęzi.

Konwersja „spaghetti testów” na sensowny zestaw regresyjny

W wielu projektach testy jednostkowe i integracyjne narastały latami bez spójnego planu. Wynik: dublujące się przypadki, brak pokrycia scenariuszy krytycznych, długa i niestabilna paczka testów. Modele mogą wesprzeć porządki w tym obszarze.

Praktyczny sposób pracy:

  1. Wrzuć serię testów z jednego modułu (np. kilka klas testowych) i poproś o:
    • listę scenariuszy biznesowych pokrytych przez testy,
    • wskazanie obszarów, które wydają się nieprzetestowane.
  2. Poproś o propozycję grupowania testów według kategorii (szczęśliwe ścieżki, błędy walidacji, błędy sieci, edge-case’y).
  3. Na końcu wygeneruj z pomocą modelu checklistę regresyjną dla danego modułu: listę warunków, które muszą być spełnione, aby uznać, że „nie popsuliśmy nic ważnego”.

Taką checklistę można potem realizować zarówno testami automatycznymi, jak i manualnymi (QA). Kluczowe jest to, że model wykonuje za ciebie intelektualnie nudną robotę: przeglądanie dziesiątek bardzo podobnych testów i ekstrakcję sensu.

Przyspieszanie code review z pomocą AI

Przy większych PR-ach część czasu schodzi na przejście przez wszystkie pliki i wychwycenie oczywistości: nieużywane importy, duplikaty, brak null-checków, spóźnione walidacje wejścia. Ten etap można śmiało oddać modelowi, zostawiając sobie decyzje architektoniczne i biznesowe.

Przykładowy tryb pracy:

  1. Eksportujesz diff z PR-a (albo kluczowe pliki) i wklejasz do modelu z opisem kontekstu: co w ogóle jest celem zmiany.
  2. Prosisz: „zachowuj się jak reviewer mid/senior w technologii X, skup się na błędach, nie na stylu, wypisz komentarze w formie bullet pointów z odniesieniem do fragmentu kodu (np. nazwą metody).”
  3. Na tej podstawie robisz pierwszą rundę poprawek, a dopiero potem wysyłasz PR do zespołu.

Efekt uboczny: człowiek-reviewer dostaje już wstępnie „odszumiony” kod i może poświęcić więcej energii na to, czy nowa funkcjonalność ma sens biznesowy i nie komplikuje architektury.

Budowanie własnych „szablonów rozmów” z AI

Z biegiem czasu naturalnie powstaje zestaw promptów, które często się powtarzają: prośby o analizę błędu, wyjaśnienie modułu, refaktoryzację, generowanie testów. Warto (dosłownie) zbudować z nich swój mini-„framework” pracy z modelem.

Prosty workflow:

  • Załóż repo lub folder w notatniku (np. ai-prompts/).
  • Twórz tam pliki typu:
    • debugging-backend.md,
    • analyze-legacy-class.md,
    • refactor-with-tests.md.
  • Każdy plik zawiera:
    • szkielet promptu z miejscami na wypełnienie (kontekst, fragment kodu, oczekiwany efekt),
    • 2–3 przykłady pytań follow-up (co zadać modelowi w następnej turze).

Przykład szablonu dla analizy klasy:

Kontekst:
- język / framework:
- rola modułu w systemie:
- ograniczenia (wydajność, bezpieczeństwo, legacy, "nie zmieniamy publicznego API"):

Kod do analizy:
[Wklej klasę / funkcje]

Zadania:
1) Opisz krok po kroku, co robi ten kod (bez pomijania edge-case'ów).
2) Wypisz potencjalne problemy projektowe / wydajnościowe / bezpieczeństwa.
3) Zaproponuj jeden mały krok refaktoryzacji, który:
   - nie zmienia zachowania,
   - zmniejsza złożoność,
   - można objąć sensownym testem.

Taki reużywalny „toolkit promptów” skraca czas startu każdej nowej sesji z AI. Przestajesz za każdym razem wymyślać, jak zadać pytanie, i skupiasz się na treści problemu. Jednocześnie styl odpowiedzi staje się bardziej przewidywalny, bo model stale dostaje podobnie ustrukturyzowane zadania.

Najczęściej zadawane pytania (FAQ)

Jakie zadania programisty najlepiej nadają się do automatyzacji z pomocą AI?

Najlepiej sprawdzają się zadania powtarzalne, przewidywalne i o niskim „creative load” (mało decyzji projektowych, dużo rzemieślniczej pracy). Chodzi o rzeczy, które robisz kilka razy w tygodniu i jesteś w stanie jasno opisać wejście i oczekiwane wyjście.

Typowe przykłady to: generowanie CRUD-ów w tym samym stylu, tworzenie testów jednostkowych według wzorca, pisanie prostych migracji, tłumaczenie kodu między wersjami frameworków, szablony endpointów API czy składanie dokumentacji z komentarzy w kodzie. Kluczowa logika biznesowa i projektowanie architektury to nadal domena człowieka, AI może tam jedynie doradzać.

Czym jest „stack AI” w pracy programisty i z czego się składa?

„Stack AI” to zestaw konkretnych narzędzi i procedur, które wspierają codzienną pracę developerską. To nie jedno magiczne narzędzie, tylko dobrze zgrany ekosystem używany w różnych punktach dnia.

Typowy stack obejmuje: model językowy (LLM) do rozmów technicznych, asystenta zintegrowanego z IDE (VS Code, JetBrains, Vim), dedykowane narzędzia developerskie (Copilot, CodeWhisperer, Tabnine, analizery diffów, generator opisów PR, skanery bezpieczeństwa z AI) oraz własne workflowy CI/CD korzystające z tych modeli. Do tego dochodzi „miękka” część – nawyki i procedury, kiedy i jak z tego korzystasz.

Jak zacząć wykorzystywać AI w codziennej pracy developera bez rewolucji w projekcie?

Najprościej zacząć od jednego modelu czatowego i jednego asystenta IDE. Przez tydzień świadomie wrzucaj do AI wszystko, co cię nuży: generowanie prostych testów, pisanie boilerplate’u, formułowanie opisów PR, drobne refaktoryzacje. Równolegle prowadź krótkie notatki, ile czasu to zajmowało wcześniej i ile teraz.

Praktyczny start: zrób tygodniową listę „irytujących” zadań (np. „testy dla serwisu X – 2h”, „update dokumentacji API – 45 min”) i do każdego dopisz, jak AI może pomóc: generowanie kodu, podpowiedzi w IDE, automatyczne szablony. Po kilku dniach widać powtarzające się kategorie, z których można zbudować pierwszą wersję własnego stacka.

Jak realistycznie ocenić, czego mogę oczekiwać od AI w programowaniu?

AI nie jest juniorem „na zdalnym”, tylko probabilistycznym modelem tekstowym. Świetnie działa tam, gdzie problem jest podobny do tysięcy przykładów z danych treningowych: standardowe integracje, popularne biblioteki, typowe bugi. Dużo gorzej radzi sobie z nietypową domeną biznesową i unikalną architekturą.

Rozsądne oczekiwania: AI przyspiesza pisanie boilerplate’u, podsuwa typowe pułapki (czas, null, concurrency, transakcje), układa myślenie o problemie i generuje pierwsze wersje testów, migracji czy dokumentacji. Decyzje architektoniczne, ocena całości systemu, bezpieczeństwo i zgodność z wymaganiami zostają po twojej stronie.

Jak zmapować własny dzień pracy, żeby znaleźć miejsca pod automatyzację AI?

Dobrym krokiem jest rozbicie dnia na mikro-zadania zamiast patrzenia na poziom „robię feature X”. W praktyce to: czytanie zgłoszeń (Jira, GitHub Issues), analiza wymagań, projektowanie rozwiązań, implementacja, testy, debugowanie, code review, dokumentacja i komunikacja w zespole.

Gdy spojrzysz na to w takiej granulacji, często okazuje się, że najwięcej „tarcia” jest nie przy samym pisaniu kodu, ale przy testach, dokumentacji czy ciągłym przepisywaniu podobnych fragmentów logiki. To są najlepsze kandydaty do wprowadzenia AI – nawet jeśli każde z osobna wydaje się małe, w skali tygodnia robi się z tego kilka godzin.

Jak użyć AI do analizy własnej pracy i znalezienia nowych obszarów automatyzacji?

Można potraktować AI jako „lupę diagnostyczną”. Na koniec dnia spisz krótko, co robiłeś(aś), bez wrażliwych danych, i wrzuć to do modelu z pytaniem: które z tych zadań da się częściowo zautomatyzować i w jaki sposób. Dobry prompt opisuje rolę (np. backend dev), listę czynności oraz prośbę o konkretne workflowy.

Efekt bywa zaskakujący – obok oczywistości typu generowanie testów czy boilerplate’u pojawiają się mniej intuicyjne propozycje: automatyczne podsumowania diffów, generowanie opisów PR na podstawie zmian, półautomatyczne tworzenie zapytań SQL z opisu w naturalnym języku. To dobry sposób na systematyczne rozszerzanie własnego stacka AI.

Czy refaktoryzację starego modułu da się sensownie wesprzeć AI?

Tak, ale nie na zasadzie „wrzuć plik i wygeneruj nowy moduł”. Sensowny scenariusz to praca iteracyjna: najpierw prosisz model o analizę aktualnej struktury (warstwy, odpowiedzialności, zależności), potem o propozycję podziału na mniejsze kroki refaktoryzacji, a następnie używasz AI do generowania lokalnych zmian: pojedynczych funkcji, testów, migracji konfiguracji.

Tip: AI dobrze działa jako „drugi mózg” przy projektowaniu docelowego kształtu API, sugerowaniu wzorców projektowych (np. wyciągnięcie strategii, adapterów) i pisaniu testów regresyjnych zabezpieczających kluczową logikę. Ocenę, co faktycznie wdrożyć i w jakiej kolejności, zostawiasz po swojej stronie.

Źródła informacji

  • The State of Developer Ecosystem 2023. JetBrains (2023) – Dane o pracy programistów, narzędziach, IDE, testach i dokumentacji
  • GitHub Copilot Research: Quantifying AI’s Impact on Developer Productivity. GitHub (2022) – Badanie wpływu asystentów AI na szybkość i jakość kodowania
  • Stack Overflow 2023 Developer Survey. Stack Overflow (2023) – Statystyki użycia narzędzi AI, typowe zadania programistów, workflow
  • IEEE Guide for the Use of Artificial Intelligence in Software Engineering. IEEE – Wytyczne użycia AI w procesie wytwarzania oprogramowania
  • Software Engineering Body of Knowledge (SWEBOK V3.0). IEEE Computer Society (2014) – Standardowe aktywności inżynierii oprogramowania, testy, dokumentacja
  • Accelerate: The Science of Lean Software and DevOps. IT Revolution Press (2018) – Metryki efektywności zespołów dev, automatyzacja CI/CD i testów
  • Continuous Delivery: Reliable Software Releases through Build, Test, and Deployment Automation. Addison-Wesley (2010) – Praktyki automatyzacji pipeline’ów, testów i wdrożeń
  • Clean Code: A Handbook of Agile Software Craftsmanship. Prentice Hall (2008) – Standardy jakości kodu, refaktoryzacja, rola testów i code review
  • Refactoring: Improving the Design of Existing Code. Addison-Wesley Professional (2018) – Techniki refaktoryzacji, przykłady powtarzalnych zmian w kodzie
  • Software Engineering at Google: Lessons Learned from Programming Over Time. O’Reilly Media (2020) – Praktyki skalowania developmentu, code review, dokumentacja, automatyzacja