Blog Dla Programistów C#/.NET

Jak programować z AI w C# i .NET? 5 nawyków: specyfikacja, code review, małe kroki, testy i architektura

piątek, 9 października 2026 Tagi: C#/.NETProgramowanieAI

Przez ostatni rok większość mojego kodu napisało AI. I muszę się przyznać do czegoś niewygodnego: przez pierwsze tygodnie ten kod był gorszy niż wtedy, gdy wszystko pisałem sam. Więcej bugów, więcej poprawek, więcej frustracji.

Nie dlatego, że AI jest słabe. Problem leżał po mojej stronie: pracowałem z nim tak, jakby nic się nie zmieniło - jak z trochę szybszym autouzupełnianiem. A zmieniło się wszystko. Pair programming z AI wymaga innych nawyków niż samodzielne pisanie kodu i dopóki ich nie zmieniłem, AI zamiast mnie przyspieszać, produkowało bugi na produkcję.

W tym artykule pokażę Ci 5 nawyków, które musiałem zmienić, żeby AI naprawdę przyspieszyło moją pracę: od pisania promptów, przez code review i testy, aż po architekturę. Każdy na konkretnym przykładzie z C# i .NET - łącznie z kodem, w którym możesz sam poszukać błędów. Na końcu dostaniesz mój szablon prompta, którego używam codziennie - do skopiowania i użycia od razu.

Przykłady są napisane w C# 12 i .NET 8 (z EF Core i xUnit), ale same nawyki nie zależą ani od wersji frameworka, ani od narzędzia. Tak samo sprawdzą się z GitHub Copilotem, Claude Code czy ChatGPT.

Jak programować z AI w C# i .NET? 5 nawyków: specyfikacja, code review, małe kroki, testy i architektura

Szybciej nie znaczy lepiej


Zacznijmy od niewygodnej prawdy: AI pisze kod szybciej niż Ty. Zawsze. Tego wyścigu nie wygrasz i nie ma sensu próbować.

Ale szybciej nie znaczy lepiej. Kod, który powstaje w 10 sekund i którego nikt w zespole nie rozumie, to nie przewaga. To dług techniczny na sterydach - rośnie szybciej niż kiedykolwiek, bo produkujesz go w tempie maszyny, a spłacasz w tempie człowieka.

Cała gra polega więc na tym, żeby połączyć tempo AI z Twoją wiedzą. AI dostarcza prędkość, a Ty kontekst, ocenę i odpowiedzialność. Tego właśnie dotyczy 5 nawyków, które omawiam poniżej:

1. Najpierw intencja, potem kod.
2. AI to junior - rób code review.
3. Małe kroki zamiast wielkich promptów.
4. Testy pilnują AI.
5. AI od taktyki, Ty od strategii.

Każdy nawyk kończy się jedną zasadą, którą łatwo zapamiętać. Razem tworzą prosty system pracy z AI, który możesz wdrożyć od jutra.

Nawyk #1: najpierw intencja, potem kod


Przestań myśleć klawiaturą. Przez lata mój odruch był prosty: jest zadanie - otwieram IDE i piszę kod. Myślałem klawiaturą: rozwiązanie krystalizowało się w trakcie pisania. Przy pracy w pojedynkę to działa całkiem nieźle, bo cały kontekst masz w głowie.

Z AI ten odruch musiałem wyłączyć. AI nie ma dostępu do Twojej głowy - ma tylko to, co mu napiszesz. Dlatego teraz najpierw opisuję, CO chcę osiągnąć: wymagania, ograniczenia, przypadki brzegowe. Dopiero potem powstaje kod. Brzmi banalnie? Zobacz różnicę w praktyce.

Słaby prompt. Tak wyglądały moje prompty na początku:

Napisz walidację NIP-u.

AI coś wygeneruje, ale nie zna Twojego projektu - więc zgaduje. Typowe skutki:

• wymyśla własne konwencje zamiast Twoich,
• rzuca wyjątkami tam, gdzie w Twoim projekcie zwraca się Result,
• sprawdza sam format, a nie sumę kontrolną - więc przepuszcza numery, które nie mogą być prawdziwym NIP-em.

Kod niby działa, ale nie pasuje do niczego. I zaczyna się poprawianie: "nie, bez wyjątków", "uwzględnij myślniki", "dodaj sumę kontrolną"... Kilka rund dopisywania tego, co mogłeś opisać na starcie.

Dobry prompt. A to ten sam prompt po zmianie nawyku:

Napisz metodę walidującą polski NIP.
Wymagania:
- C# 12, .NET 8
- zwraca bool, nie rzuca wyjątków
- ignoruje myślniki i spacje
- sprawdza sumę kontrolną, nie tylko format
- bez zewnętrznych bibliotek
Dodaj testy xUnit: poprawny NIP,
zła suma kontrolna, null, pusty string.

Co się zmieniło? Prompt mówi wprost:

• wersję języka i frameworka - AI nie musi zgadywać, jakiej składni może użyć,
• sposób obsługi błędów - bool zamiast wyjątków, zgodnie z konwencją projektu,
• co dokładnie sprawdzać - łącznie z myślnikami, spacjami i sumą kontrolną,
• czego nie używać - żadnych zewnętrznych bibliotek,
• jakie testy dopisać - razem z przypadkami brzegowymi: null i pusty string.

Napisanie takiego prompta zajmuje 1 minutę, a oszczędza ok. 30 minut poprawek. I zauważ - to nie jest żaden magiczny prompt engineering. To zwykła specyfikacja. Coś, co dobry programista i tak powinien umieć napisać: dla kolegi z zespołu, w tickecie czy w opisie pull requesta.

Zasada #1: AI nie czyta Ci w myślach. Nieprecyzyjny prompt = losowy kod. Piszesz specyfikację, nie życzenie.

Nawyk #2: AI to junior - rób code review


AI to junior. Bardzo zdolny, bardzo pewny siebie... i czasem w błędzie. Właśnie ta pewność siebie jest największym problemem.

Pułapka ładnego kodu. Kod od AI ma jedną cechę, która czyni go niebezpiecznym: świetnie wygląda. Kompiluje się. Ma ładne nazwy. Wygląda, jakby pisał go senior. I właśnie dlatego wyłącza Ci czujność.

Kod, który wygląda źle, czytasz uważnie. Kod, który wygląda dobrze, łatwo tylko przelecieć wzrokiem. A AI potrafi ukryć subtelnego buga w najładniejszym kodzie, jaki dziś zobaczysz.

Test: znajdź 3 błędy. Sprawdźmy to w praktyce. Poniżej kod w stylu, jaki naprawdę dostaję od AI. Wygląda porządnie, ale są w nim 3 błędy. Zanim przeczytasz dalej, spróbuj je znaleźć sam - to najlepszy sposób, żeby coś realnie wynieść z tego artykułu.

public async void SaveOrderAsync(Order order)
{
var discount = GetDiscount(order.CreatedAt);
order.Total -= discount;
_db.Orders.Add(order);
_db.SaveChanges();
}

private decimal GetDiscount(DateTime createdAt)
=> createdAt.Date == DateTime.Now.Date ? 10m : 0m;

Rozwiązanie. Sprawdzamy:

1. async void. Jeśli w takiej metodzie poleci wyjątek, nie złapiesz go normalnie poza nią. Wywołujący nie może jej nawet await-ować, więc nie wie, kiedy (i czy w ogóle) zapis się zakończył. W ASP.NET Core nieobsłużony wyjątek z async void potrafi wręcz położyć cały proces. Poza event handlerami zawsze wybieraj async Task.

2. SaveChanges() zamiast SaveChangesAsync(). W metodzie asynchronicznej robimy synchroniczny zapis do bazy, który blokuje wątek na czas całego zapytania. Pod obciążeniem to prosta droga do wyczerpania puli wątków.

3. DateTime.Now. Wystarczy, że serwer stoi w innej strefie czasowej (w chmurze i w kontenerach to częste - zwykle działają w UTC), i nagle rabaty naliczają się w złych godzinach. Rozwiązanie: UtcNow albo świadomie obsłużona strefa czasowa.

Poprawiona wersja może wyglądać tak:

public async Task SaveOrderAsync(Order order, CancellationToken ct = default)
{
var discount = GetDiscount(order.CreatedAt);
order.Total -= discount;
_db.Orders.Add(order);
await _db.SaveChangesAsync(ct);
}

/* CreatedAt trzymamy w UTC, więc porównujemy z UtcNow */
private decimal GetDiscount(DateTime createdAtUtc)
=> createdAtUtc.Date == DateTime.UtcNow.Date ? 10m : 0m;

Jeśli "dzisiaj" ma oznaczać dzień w polskiej strefie czasowej (np. promocja ważna do północy czasu polskiego), przelicz obie daty przez TimeZoneInfo, zamiast polegać na strefie, w której akurat stoi serwer.

Ile błędów udało Ci się znaleźć? Jeśli wszystkie 3 - świetnie. Jeśli mniej, to najlepszy dowód na to, że ładny kod usypia czujność. A w prawdziwym projekcie taki fragment byłby jednym z kilkunastu w pull requeście.

Checklista review kodu od AI w .NET. Z czasem wyrobiłem sobie krótką checklistę, przez którą przepuszczam każdy kod od AI:

• Async: czy nie ma async void i czy CancellationToken jest przekazywany dalej.

• Daty: UtcNow, nie Now.

• EF Core: czy nie ma problemu N+1 (np. doczytywania pozycji każdego zamówienia osobnym zapytaniem w pętli) i czy przy samym odczycie jest AsNoTracking - śledzenie zmian kosztuje, a do wyświetlenia danych nie jest potrzebne.

• Wyjątki: czy nic nie połyka błędów pustym catchem.

• Bezpieczeństwo: parametry w SQL, walidacja wejścia.

5 punktów, 30 sekund - i wyłapujesz typowe wpadki, zanim trafią na produkcję. Zwróć uwagę, że poprawiony kod z przykładu wyżej przechodzi już 2 pierwsze punkty: ma async Task, przekazuje CancellationToken do SaveChangesAsync i korzysta z UtcNow.

Zasada #2: nie wypuszczasz kodu juniora bez review. Nie wypuściłbyś na produkcję kodu juniora, którego nikt nie przejrzał. Kodu od AI też nie wypuszczaj.

Nawyk #3: małe kroki zamiast wielkich promptów


Prompt to nie list do Świętego Mikołaja. Im więcej życzeń w nim upchniesz, tym mniejsza szansa, że dostaniesz to, czego naprawdę potrzebujesz.

Było: cały moduł w jednym prompcie. Na początku robiłem tak:

Napisz mi cały moduł faktur: encje, serwisy, API, walidację i testy.

I AI pisało. 800 linii, 20 plików naraz. Wywołania metod, których w moim projekcie w ogóle nie ma. Review czegoś takiego? Nierealne. Więc co robiłem? Wklejałem i modliłem się, żeby działało. To nie jest programowanie. To hazard.

Jest: dekompozycja. Teraz ten sam moduł dzielę na 5 kroków:

1. Model: Invoice + InvoiceLine.
2. Liczenie sum i VAT-u - od razu z testami.
3. Numeracja faktur - też z testami.
4. Endpoint POST /invoices.
5. Walidacja żądania.

Reguła jest prosta: 1 krok = 1 prompt = 1 review. Każdy kawałek rozumiem, zanim przejdę dalej. A każdy kolejny prompt opiera się na kodzie, który już jest w projekcie i który sprawdziłem, a nie na wyobrażeniach AI o tym, co mogłoby tam być.

Dlaczego to działa? Z 3 powodów:

• Mniej halucynacji. Mały kontekst = mniej zgadywania. AI nie musi wymyślać połowy projektu.

• Review w 2 minuty. Mały kawałek kodu przeglądasz jak mały pull request, a nie jak 20 plików naraz.

• Błąd łapiesz od razu. W kroku 2, a nie w kroku 47, kiedy wszystko jest już posklejane i nie wiadomo, od czego zacząć szukanie.

Zasada #3: prompt jak pull request. Mały, konkretny, do przejrzenia w 5 minut. Jeśli wyniku prompta nie da się przejrzeć w 5 minut, to znak, że krok jest za duży i trzeba go podzielić.

Nawyk #4: testy najpierw - to one pilnują AI


Prompt można zrozumieć opacznie. Czerwonego testu nie da się zagadać.

Nowy flow. Mój sposób pracy wygląda teraz tak:

1. Ty piszesz test (albo bardzo dokładnie go przeglądasz).
2. AI pisze implementację.
3. Testy weryfikują, czy implementacja dowozi.

Test to specyfikacja, której AI nie może zignorować. Z promptem można dyskutować, z testem nie: albo przechodzi, albo nie.

Jeśli brzmi to znajomo, to nie przypadek - to stare, dobre podejście test-first, znane z TDD. AI tylko sprawiło, że opłaca się ono bardziej niż kiedykolwiek: Ty definiujesz, co ma działać, a AI szybko dowozi, jak.

Przykład: testy jako wymagania. Piszę test do kalkulatora VAT-u: Polska - 23%, Niemcy - 19%.

[Theory]
[InlineData("PL", 100, 23)]
[InlineData("DE", 100, 19)]
public void Calculate_ReturnsCorrectVat(
string country, decimal net, decimal expected)
{
var vat = VatCalculator.Calculate(country, net);
Assert.Equal(expected, vat);
}

I teraz prompt jest banalnie prosty:

Zaimplementuj VatCalculator tak, żeby te testy przeszły.

Nie opisuję wymagań prozą. Testy SĄ wymaganiami. A gdy dojdzie kolejny kraj, dopisujesz 1 linijkę InlineData i AI znowu ma jasny, sprawdzalny cel.

Pułapka: test, który nic nie testuje. Uwaga jednak na drugą stronę medalu. Jeśli poprosisz AI, żeby samo napisało testy do swojego kodu, często dostaniesz coś takiego:

[Fact]
public void Calculate_Works()
{
var result = VatCalculator.Calculate("PL", 100);
Assert.True(result >= 0); /* zawsze przejdzie */
}

Ten test sprawdza... że wynik jest większy lub równy zero. Czyli nic. Zielony pasek, zero wartości. Zielony pasek to jeszcze nie poprawny kod.

A bywa gorzej: jeśli w kodzie jest bug, AI potrafi napisać test, który ten bug utrwala - test napisany pod implementację, a nie pod wymagania. Wtedy masz nie tylko błąd, ale też test, który go broni. Dlatego testom od AI patrz na ręce podwójnie.

Zasada #4: kod albo testy - jedno kontrolujesz Ty. AI może pisać kod albo testy, ale kontrola nad przynajmniej jednym z nich musi zostać u Ciebie. Inaczej lis pilnuje kurnika.

Nawyk #5: AI od taktyki, Ty od strategii


Ostatni nawyk jest moim zdaniem najważniejszy: architektura zostaje u Ciebie.

Podział ról. Tak dzielę robotę:

• AI robi taktykę: metody i klasy, refactoring, testy jednostkowe, cały boilerplate - DTO, mapowania, konfiguracja. To robi szybciej ode mnie i zwykle dobrze.

• Ty decydujesz o strategii: architektura i granice modułów, wybór technologii, bezpieczeństwo i dane. I ocena, co jest świadomym kompromisem, a co zwykłym przegięciem.

Przykład z życia: over-engineering. Poprosiłem kiedyś AI o prosty zapis encji do bazy. Wystarczyłyby 2 linijki:

_db.Customers.Add(customer);
await _db.SaveChangesAsync(ct);

A co dostałem? Generyczne IRepository<T>, do tego IUnitOfWork, RepositoryFactory i 3 warstwy abstrakcji. Wszystko to nad EF Core, który sam jest oparty o wzorce Repository i Unit of Work: DbSet pełni rolę repozytorium, a DbContext - jednostki pracy. Dostałem abstrakcję nad abstrakcją, której nikt nie potrzebował.

Dlaczego AI przekombinowuje? Są 3 powody:

• Widziało mnóstwo tutoriali. A tutoriale uwielbiają wzorce projektowe.

• Nie zna Twojego projektu. Ani zespołu, ani deadline'u, ani tego, że ten serwis ma być prosty.

• Nie poniesie konsekwencji. To Ty będziesz ten kod utrzymywać. To Ty będziesz go tłumaczyć koledze za rok.

Częściowo pomaga tu nawyk #1: w wymaganiach możesz wprost napisać, czego AI ma nie robić (np. "bez dodatkowych warstw abstrakcji nad EF Core"). Ale sama ocena, czy dana abstrakcja jest potrzebna, zawsze należy do Ciebie.

Zasada #5: AI proponuje, Ty decydujesz. Bo w git blame będzie Twoje nazwisko, nie jego.

Bonus: mój szablon prompta


Na koniec obiecany bonus: szablon prompta, którego używam codziennie. Ma 4 sekcje:

KONTEKST:  [projekt, .NET 8, biblioteki, konwencje]
ZADANIE: [JEDNA konkretna rzecz]
WYMAGANIA:
- [ograniczenia i konwencje]
- [czego NIE robić]
FORMAT: [sam kod / kod + wyjaśnienie / diff]

• KONTEKST: w czym pracujesz - wersja .NET-a, biblioteki, konwencje projektu.

• ZADANIE: jedna konkretna rzecz. Nie 3 - jedna.

• WYMAGANIA: ograniczenia i, bardzo ważne, czego AI ma NIE robić.

• FORMAT: sam kod, kod z wyjaśnieniem albo diff.

Ten szablon spina wszystkie 5 nawyków w jednym prompcie. Kontekst i wymagania to intencja przed kodem (nawyk #1). Jedno zadanie to mały krok (#3). W wymaganiach możesz od razu wskazać testy, które implementacja ma przejść (#4). "Czego NIE robić" pilnuje, żeby AI nie podejmowało za Ciebie decyzji architektonicznych (#5). A format z uzasadnieniem decyzji ułatwia review (#2).

Szablon w akcji. Tak to wygląda wypełnione:

KONTEKST: API w .NET 8, minimal API, EF Core 8,
Postgres. Konwencja: Result zamiast wyjątków.
ZADANIE: Endpoint POST /api/customers.
WYMAGANIA:
- email wymagany i unikalny
- 201 + lokalizacja albo 400 + lista błędów
- mapowanie ręczne, bez AutoMappera
- NIE zmieniaj innych plików
FORMAT: kod + krótkie uzasadnienie decyzji

Zwróć uwagę na linijkę "NIE zmieniaj innych plików". Ta jedna linijka uratowała mi więcej czasu niż niejeden kurs - bo AI uwielbia "przy okazji" poprawić coś obok. Ta linijka mu tego zabrania.

Ściąga: 5 nawyków w pigułce


NawykStary odruchNowy nawykZasada
1. Najpierw intencjaotwieram IDE i piszę, prompt w 1 zdaniuwymagania, ograniczenia i przypadki brzegowe przed kodemAI nie czyta Ci w myślach
2. AI to juniorładny kod = dobry kodreview z checklistą: async, daty, EF Core, wyjątki, bezpieczeństwokodu od AI nie wypuszczasz bez review
3. Małe krokicały moduł w jednym prompcie1 krok = 1 prompt = 1 reviewprompt jak pull request
4. Testy pilnują AIAI pisze kod i testy do niegoTy piszesz (albo dokładnie przeglądasz) testy, AI implementacjękod albo testy - jedno kontrolujesz Ty
5. AI od taktykiAI decyduje o architekturzeAI: metody, testy, boilerplate. Ty: architektura, technologie, bezpieczeństwoAI proponuje, Ty decydujesz


Podsumowanie


Pair programming z AI to nie wyścig na szybkość, tylko podział pracy. Zbierzmy wszystko w jednym miejscu:

• Najpierw intencja, potem kod - piszesz specyfikację, nie życzenie.
• Review jak dla juniora - ładny kod też potrafi mieć buga.
• Małe kroki - 1 krok = 1 prompt = 1 review.
• Testy pilnują AI - kod albo testy, jedno kontrolujesz Ty.
• Architektura należy do Ciebie - AI proponuje, Ty decydujesz.

I jedna rzecz, na którą warto zwrócić uwagę: żaden z tych nawyków nie jest tak naprawdę "o AI". To po prostu nawyki dobrego programisty - nawyki seniora. AI tylko sprawiło, że stały się obowiązkowe.

AI nie zabierze Ci pracy. Ale programista, który umie z nim pracować, będzie po prostu szybszy od Ciebie. Dobra wiadomość jest taka, że tego da się nauczyć. Otwórz dziś swój projekt i przetestuj chociaż jeden z tych nawyków - najprościej zacząć od szablonu prompta.

A jeśli chcesz iść krok dalej, mam dla Ciebie coś więcej niż jeden szablon. Przygotowałem darmowy PDF: 25 gotowych promptów AI dla programistów C#/.NET. 5 kategorii po 5 promptów: refaktoryzacja, testy jednostkowe, debugowanie, code review oraz legacy i dokumentacja, a do tego 3 zasady pracy z AI. Kopiujesz, wklejasz i od razu masz lepszy punkt startu - to esencja mojego codziennego workflow.

Odbierzesz go tutaj: modestprogrammer.pl/25-promptow. Zostawiasz maila i PDF przychodzi od razu. Przy okazji dołączasz do społeczności ponad 10 000 programistów .NET: raz w tygodniu 1 konkretny mail - newsy ze świata .NET i AI oraz rabaty na moje kursy, których nie znajdziesz nigdzie indziej. Zero spamu, sama treść.

Powodzenia w pair programmingu z AI :)

Autor artykułu:
Kazimierz Szpin
Kazimierz Szpin
CTO & Founder - FindSolution.pl
Programista C#/.NET. Specjalizuje się w Blazor, ASP.NET Core, ASP.NET MVC, ASP.NET Web API, WPF oraz Windows Forms.
Autor bloga ModestProgrammer.pl
Dodaj komentarz
© Copyright 2026 modestprogrammer.pl | Sztuczna Inteligencja | Regulamin | Polityka prywatności. Design by Kazimierz Szpin. Wszelkie prawa zastrzeżone.