Dowiedz się, jak logika aplikacji generowana przez AI może być szybka, czytelna i prosta — oraz poznaj praktyczne prompty, listy kontrolne do przeglądu i wzorce dla kodu łatwego w utrzymaniu.

text\nWrite application logic for X.\nAcceptance criteria: ...\nNon-goals: ...\nConstraints: latency ..., data size ..., concurrency ..., memory ...\nDeliver:\n1) Simple version (most readable)\n2) Optimized version (explain the trade-offs)\nAlso: explain time/space complexity in plain English and note any edge cases.\n\n\n### Wymagaj wyjaśnień i złożoności prostym językiem\n\nPoproś model o uzasadnienie kluczowych wyborów („dlaczego ta struktura danych”, „dlaczego taki porządek rozgałęzień”) i oszacowanie złożoności bez żargonu. Ułatwia to przegląd, testowanie i podjęcie decyzji, czy optymalizacja jest warta dodanej złożoności.\n\n## Wzorce, które utrzymują czytelność generowanej przez AI logiki\n\nCzytelna logika aplikacji rzadko zależy od wymyślnej składni. Chodzi o to, by następna osoba (często przyszłe ja) zrozumiała, co kod robi na pierwszy rzut oka. Gdy używasz AI do generowania logiki, kilka powtarzalnych wzorców daje najlepsze rezultaty.\n\n### Trzymaj funkcje małe i jednozadaniowe\n\nAI ma skłonność do „pomocnego” łączenia walidacji, transformacji, persystencji i logowania w jednej dużej funkcji. Naciskaj na mniejsze jednostki: jedna funkcja waliduje wejście, druga oblicza wynik, trzecia zapisuje.\n\nPrzydatna zasada: jeśli nie potrafisz opisać zadania funkcji w jednym krótkim zdaniu bez „i”, prawdopodobnie robi za dużo.\n\n### Preferuj prosty przepływ sterowania\n\nCzytelna logika faworyzuje oczywiste rozgałęzienia zamiast sprytnego zagęszczania. Jeśli warunek jest ważny, zapisz go jako czytelny blok if, a nie jako zagnieżdżony ternary lub łańcuch trików boolean.\n\nGdy widzisz wyjście AI typu „rób wszystko w jednym wyrażeniu”, poproś o „early returns” i „guard clauses”. To często redukuje zagnieżdżenia i uwidacznia ścieżkę szczęścia.\n\n### Nazwy jakimi posłuży się współpracownik\n\nZnaczące nazwy biją „uniwersalne helpery”. Zamiast processData() lub handleThing() używaj nazw, które zakodują intencję:\n\n- calculateInvoiceTotal()\n- isPaymentMethodSupported()\n- buildCustomerSummary()\n\nUważaj też na zbyt ogólne narzędzia (np. mapAndFilterAndSort()): mogą ukrywać reguły biznesowe i utrudniać debugowanie.\n\n### Komentarze o intencji, nie o mechanice\n\nAI potrafi generować obszerne komentarze, które powtarzają kod. Zachowuj komentarze tylko tam, gdzie intencja nie jest oczywista: dlaczego dana reguła istnieje, jakiego przypadku brzegowego chronisz, jakich założeń trzeba przestrzegać.\n\nJeśli kod potrzebuje wielu komentarzy, potraktuj to jako sygnał do uproszczenia struktury lub poprawy nazewnictwa — nie jako zachętę do dopisywania słów.\n\n## Wybory projektowe sprzyjające prostocie\n\nProstota rzadko oznacza „mniej kodu za wszelką cenę”. Chodzi o pisanie kodu, który współpracownik może pewnie zmienić za tydzień. AI może tu pomóc — jeśli poprowadzisz je ku wyborom utrzymującym prostotę rozwiązania.\n\n### Zacznij od najprostszej struktury danych, która działa\n\nAI często przeskakuje do sprytnych struktur (mapy map, klasy, zagnieżdżone generyki), bo wyglądają „zorganizowanie”. Sprzeciwiaj się temu. Dla większości logiki aplikacji proste listy/obiekty są łatwiejsze do rozumienia.\n\nJeśli masz mały zbiór elementów, lista z czytelnym filter/find często jest bardziej czytelna niż budowanie indeksu przedwcześnie. Wprowadź mapę/słownik dopiero, gdy wyszukiwania staną się istotne i powtarzalne.\n\n### Ogranicz warstwy abstrakcji, dopóki nie ma powtarzalnej potrzeby\n\nAbstrakcje wyglądają ładnie, ale ich nadmiar ukrywa zachowanie. Przy zamawianiu kodu od AI preferuj „jedną warstwę pośredniczącą”: małą funkcję, jasny moduł i bezpośrednie wywołania.\n\nPrzydatna zasada: nie twórz interfejsu, factory i systemu pluginów, żeby rozwiązać pojedynczy przypadek. Poczekaj na drugi lub trzeci wariant, a potem refaktoryzuj z pewnością.\n\n### Kompozycja zamiast głębokich drzew dziedziczenia\n\nDrzewka dziedziczenia utrudniają odpowiedź na pytanie: „Skąd pochodzi to zachowanie?” Kompozycja utrzymuje zależności widoczne. Zamiast class A extends B extends C wolisz małe komponenty, które jawnie łączysz.\n\nW promptach możesz napisać: „Unikaj dziedziczenia, chyba że jest stabilny kontrakt; preferuj przekazywanie helperów/usług jako parametrów.”\n\n### Używaj znanych wzorców, które zespół już rozumie\n\nAI może zaproponować wzorce technicznie poprawne, ale kulturowo obce. Znajomość jest funkcją. Poproś o rozwiązania pasujące do Twojego stacku i konwencji (nazewnictwo, struktura folderów, obsługa błędów), żeby wynik naturalnie wszedł do przeglądu i utrzymania.\n\n## Wydajność bez utraty czytelności\n\nPrace nad wydajnością idą źle, gdy optymalizujesz niewłaściwą rzecz. Najlepszy „szybki” kod to często po prostu odpowiedni algorytm zastosowany do realnego problemu.\n\n### Wybierz właściwy algorytm przed strojeniem\n\nZanim poprawisz pętle czy jednowierszówki, upewnij się, że używasz sensownego podejścia: mapa skrótu zamiast powtarzanych wyszukiwań liniowych, set do sprawdzeń przynależności, jedno przejście zamiast kilku skanów. Przy zamówieniu pomocy AI bądź konkretny w ograniczeniach: oczekiwany rozmiar wejścia, czy dane są posortowane i co oznacza „wystarczająco szybkie”.\n\nProsta zasada: jeśli złożoność jest nieodpowiednia (np. O(n²) na dużych listach), żadna mikrooptymalizacja tego nie uratuje.\n\n### Mierz najpierw (na realnych danych)\n\nNie zgaduj. Użyj podstawowego profilowania, lekkich benchmarków i — co najważniejsze — realistycznych wolumenów danych. Kod generowany przez AI może wyglądać efektywnie, a ukrywać kosztowne operacje (powtarzane parsowanie, dodatkowe zapytania).\n\nUdokumentuj, co zmierzyłeś i dlaczego to ma znaczenie. Krótki komentarz typu „optymalizowano pod 50k elementów; poprzednia wersja kończyła się w ~2s” pomaga przyszłym programistom nie cofać optymalizacji.\n\n### Optymalizuj tylko gorące ścieżki\n\nPozwól większości kodu być nudnym i czytelnym. Skoncentruj wysiłek wydajnościowy tam, gdzie rzeczywiście spędza się czas: ciasne pętle, serializacja, wywołania do BD, granice sieciowe. W innych miejscach preferuj czytelność ponad sprytem, nawet jeśli to kilka milisekund wolniej.\n\n### Ostrożnie stosuj cache, batching i indeksowanie\n\nTechniki te dają duże korzyści, ale zwiększają koszt mentalny.\n\n- Cache: zapisz reguły unieważniania i TTL w komentarzu przy kodzie.\n- Batching: wyjaśnij rozmiar batcha i obsługę błędów.\n- Indeksy: zanotuj, które zapytania korzystają i jaki jest koszt zapisu.Jeśli AI sugeruje któreś z tych narzędzi, poproś o „dlaczego”, kompromisy i krótki opis, kiedy usunąć optymalizację.\n\n## Testowanie jako siatka bezpieczeństwa dla logiki generowanej przez AI\n\nAI potrafi szybko wygenerować „rozsądną” logikę aplikacji, ale nie wyczuje kosztu subtelnego błędu w produkcji ani nie odczuje zamieszania wynikającego z niejasnego wymogu. Testy są buforem między pomocnym szkicem a niezawodnym kodem — szczególnie gdy później refaktoryzujesz dla wydajności lub upraszczasz zagraconą funkcję.\n\n### Proś o testy razem z kodem\n\nKiedy prosisz o implementację, poproś również o testy. Otrzymasz klarowniejsze założenia i lepiej zdefiniowane interfejsy, ponieważ model musi udowodnić zachowanie, a nie tylko je opisać.\n\nPraktyczny podział:\n\n- Testy jednostkowe dla czystych reguł biznesowych (cennik, sprawdzenia uprawnień, walidacja)\n- Testy integracyjne dla logiki „klejącej” (zapytania BD, kolejki, klienci HTTP), z użyciem fake’ów lub kontenerów testowych\n\n### Pokryj przypadki brzegowe, które AI często pomija\n\nAI ma tendencję pisać ścieżkę „happy path” jako pierwszą. Uczyń przypadki brzegowe jawne w planie testów, aby później nie polegać na pamięci czy wiedzy plemiennej. Typowe:
\n- Puste wejścia, brakujące pola, null / undefined\n- Nieoczekiwane typy lub źle sformatowane dane\n- Timeouts, retry, częściowe błędy (szczególnie przy wywołaniach sieciowych)\n- Idempotencja (bezpieczne ponowne uruchomienia) i duplikaty zdarzeń\n\n### Używaj testów tabelarycznych lub property-based dla reguł biznesowych\n\nLogika biznesowa często ma wiele drobnych wariantów („jeśli użytkownik jest X i zamówienie jest Y, to Z”). Testy tabelaryczne utrzymują to czytelne, listując wejścia i oczekiwane wyjścia w kompaktowej macierzy.\n\nJeśli reguła ma inwarianty („suma nie może być ujemna”, „rabat nigdy nie przekracza podsumowania”), testy property-based mogą eksplorować więcej przypadków niż ręcznie napisane testy.\n\n### Testy chronią refaktory i optymalizacje\n\nGdy masz dobre pokrycie, możesz bezpiecznie:\n\n- Zastępować zagnieżdżone warunki jaśniejszą strukturą\n- Dodać cache lub batching dla wydajności\n- Wydzielać helpery bez zmiany zachowania\n\nTraktuj przechodzące testy jako kontrakt: jeśli poprawisz czytelność lub szybkość, a testy nadal przechodzą, najpewniej zachowałeś poprawność.\n\n## Lista kontrolna podczas code review logiki napisanej przez AI\n\nAI może wygenerować „prawdopodobny” kod, który wygląda czysto na pierwszy rzut oka. Dobry przegląd skupia się mniej na tym, czy można było to napisać, a bardziej na tym, czy to właściwa logika dla Twojej aplikacji.\n\n### Szybka lista kontrolna\n\nUżyj tego jako szybkiego pierwszego przeglądu przed debatą o stylu czy mikrooptymalizacjach:\n\n- Poprawność: Czy odpowiada wymaganiu i przypadkom brzegowym (puste wejścia, null, duplikaty, strefy czasowe, zaokrąglenia)? Czy błędy są obsłużone celowo?\n- Czytelność: Czy współpracownik po jednym przeczytaniu potrafi wyjaśnić przepływ? Czy nazwy są specyficzne (isEligibleForDiscount vs flag)?\n- Złożoność: Czy logika jest bardziej skomplikowana niż konieczne (zagnieżdżone warunki, gęste jednowierszówki, przedwczesne abstrakcje)?\n- Duplikacja: Czy AI powtórzyło logikę w wielu gałęziach zamiast ją scentralizować?\n\n### Uważaj na ukrytą złożoność\n\nAI często „rozwiązuje” problem, grzebiąc złożoność w szczegółach, które łatwo przeoczyć:\n\n- Magiczne liczby i stringi: Zamień na stałe lub enumy i dodaj komentarz tylko wtedy, gdy powód nie jest oczywisty.\n- Niejasny stan: Uważaj na kod mutujący współdzielone obiekty, aktualizujący zmienne w wielu gałęziach lub polegający na implicytnych wartościach domyślnych.\n- Efekty uboczne: Sprawdź, czy helpery „czyste” nie wykonują logowania, wywołań sieciowych, zapisów do BD lub zmian globalnej konfiguracji.\n\n### Spójność ważniejsza niż spryt\n\nUpewnij się, że wynik przestrzega konwencji projektu (lint, struktura plików, typy błędów). Jeśli nie, popraw to teraz — niespójności stylu spowalniają refaktory i utrudniają przeglądy.\n\n### Postanów, co zatrzymać, a co przepisać ręcznie\n\nZachowaj kod AI, gdy jest prostolinijny, testowalny i zgodny z konwencjami zespołu. Przepisz, gdy widzisz:\n\n- niejasną intencję (musiałbyś dodać komentarze, by zrozumieć)\n- skomplikowany przepływ sterowania (flagi, wczesne wyjścia wszędzie, głębokie zagnieżdżenia)\n- «uniwersalne» abstrakcje, które nie pasują do domeny\n\nJeśli robisz takie przeglądy regularnie, szybko rozpoznasz, które prompty dają przeglądalny kod — potem dostroisz prompt zanim wygenerujesz kolejny raz.\n\n## Bezpieczeństwo i niezawodność\n\nGdy AI generuje logikę aplikacji, często optymalizuje „ścieżkę szczęścia”. To może pozostawić luki tam, gdzie żyją bezpieczeństwo i niezawodność: przypadki brzegowe, tryby awaryjne i domyślne wartości wygodne, ale niebezpieczne.\n\n### Nie ujawniaj sekretów (w promptach ani logach)\n\nTraktuj prompt jak komentarz w publicznym repozytorium. Nigdy nie wklejaj kluczy API, tokenów produkcyjnych, danych klientów ani wewnętrznych URL-i. Pilnuj też outputu: AI może zasugerować logowanie całych requestów, nagłówków lub obiektów wyjątków zawierających poświadczenia.\n\nProsta zasada: loguj identyfikatory, nie całe payloady. Jeśli musisz logować payloady do debugowania, domyślnie je redaguj i dołącz gate za flagą środowiskową.\n\n### Waliduj wejścia i zwracaj przewidywalne błędy\n\nKod z AI czasem zakłada dobrze sformatowane wejścia. Uczyń walidację explicite na granicach (handlery HTTP, konsumenci wiadomości, CLI). Konwertuj nieoczekiwane wejścia na spójne błędy (np. 400 vs 500) i projektuj retry, aby były bezpieczne, stawiając na idempotencję.\n\nNiezawodność to także czas: dodaj timeouts, obsłuż null-e i zwracaj strukturalne błędy zamiast niejasnych stringów.\n\n### Uważaj na niebezpieczne domyślne ustawienia\n\nGenerowany kod może zawierać skróty wygodne, ale ryzykowne:\n\n- Szerokie uprawnienia (wildcard IAM, zakresy „admin”)\n- Słabe szyfrowanie (własne hashowanie, przestarzałe algorytmy, brak soli)\n- Brak sprawdzeń autoryzacji (ufanie przesłanym przez klienta identyfikatorom użytkownika)\n\nProś o konfiguracje w trybie least-privilege i umieszczaj sprawdzenia autoryzacji blisko dostępu do danych, które mają chronić.\n\n### Wymagaj założeń bezpieczeństwa i trybów awarii\n\nPraktyczny wzorzec promptu: „Wyjaśnij założenia bezpieczeństwa, model zagrożeń i co się dzieje, gdy zależności zawiodą.” Chcesz, żeby AI stwierdziło np.: „Ten endpoint wymaga uwierzytelnionego użytkownika”, „tokeny są rotowane”, „timeouty BD zwracają 503”, itp.\n\nJeśli te założenia nie zgadzają się z rzeczywistością, kod jest błędny — nawet jeśli jest szybki i czytelny.\n\n## Utrzymywalność w czasie: kiedy refaktoryzować, a kiedy przestać\n\nAI szybko generuje czystą logikę, ale utrzymywalność zdobywa się przez miesiące: zmiany wymagań, nowi członkowie zespołu i rosnący nierównomiernie ruch. Celem nie jest bezkończyste „udoskonalanie” kodu — chodzi o utrzymanie go zrozumiałym, dopóki spełnia realne potrzeby.\n\n### Refaktoryzuj, gdy frikcja jest mierzalna\n\nRefaktoryzacja ma sens, gdy potrafisz wskazać konkretny koszt:\n\n- Wprowadzenie nowej funkcji zajmuje zauważalnie dłużej, bo logika jest splątana lub zdublowana.\n- Błędy skupiają się wokół tego samego modułu, bo odpowiedzialności są niejasne.\n- Prace nad wydajnością są zablokowane, bo kod ukrywa, gdzie spędza się czas.\n\nJeśli nic z tego nie występuje, powstrzymaj się od „sprzątania dla samego sprzątania”. Czasem duplikacja kosztuje mniej niż wprowadzenie abstrakcji, które mają sens tylko w Twojej głowie.\n\n### Dokumentuj „dlaczego”, nie tylko „co”\n\nKod wygenerowany przez AI często wygląda rozsądnie, ale przyszłe ja potrzebuje kontekstu. Dodaj krótkie notatki wyjaśniające kluczowe decyzje:\n\n- dlaczego dana sekcja była zoptymalizowana (co było wolne)\n- dlaczego coś zostało uogólnione (co się powtarzało)\n- dlaczego zachowano prostsze podejście (złożoność nie się opłacała)\n\nTrzymaj to blisko kodu (docstring, README lub krótka notatka w /docs) i powiąż z ticketami, jeśli je masz.\n\n### Dodaj lekkie diagramy dla krytycznych przepływów\n\nDla kilku kluczowych ścieżek, mały diagram zapobiega nieporozumieniom i zmniejsza ryzyko przypadkowych przepisów:\n\n\nRequest → Validation → Rules/Policy → Storage → Response\n ↘ Audit/Events ↗\n\n\nSą szybkie w utrzymaniu i pomagają recenzentom zobaczyć, gdzie umieścić nową logikę.\n\n### Zapisz „znane limity” i plany refaktora\n\nSpisz oczekiwania operacyjne: progi skalowalności, spodziewane wąskie gardła i kolejne kroki. Przykład: „Działa do ~50 requestów/sec na jednej instancji; wąskie gardło to ewaluacja reguł; następny krok to cache.”\n\nTo zamienia refaktoryzację w zaplanowaną odpowiedź na wzrost użycia, zamiast na domysły, i zapobiega przedwczesnym optymalizacjom, które szkodzą czytelności.\n\n## Praktyczny workflow, żeby utrzymać wyjście AI szybkie i zrozumiałe\n\nDobry workflow traktuje wyjście AI jako pierwszy szkic, nie gotową funkcję. Celem jest szybko uzyskać coś poprawnego i czytelnego, a potem poprawiać wydajność tylko tam, gdzie naprawdę ma to znaczenie.\n\nTu też narzędzia mają znaczenie. Jeśli używasz platformy typu vibe-coding, jak Koder.ai (chat-to-app z trybem planowania, eksportem źródła i snapshotami/rollback), stosujesz te same zasady: najpierw prosty, czytelny kod logiki aplikacji, potem iterujesz małymi, przeglądalnymi zmianami. Platforma przyspiesza szkicowanie i szkielety, ale zespół wciąż odpowiada za kompromisy.\n\n### Standardy zespołowe (ustal je przed promptowaniem)\n\nSporządź kilka domyślnych reguł, aby każde AI-generated change zaczynało z tych samych oczekiwań:\n\n- Limity złożoności: preferuj funkcje poniżej ~40–60 linii; unikaj głębokiego zagnieżdżenia; trzymaj niską złożoność cyklomatyczną (np. „żadna funkcja powyżej 10 bez uzasadnienia”).\n- Nazewnictwo: terminy domenowe zamiast technicznych (np. invoiceTotal, nie calcX); brak jednoznacznych liter poza krótkimi pętlami.\n- Cele pokrycia testami: minimalne oczekiwania (np. „nowa logika musi zawierać testy jednostkowe dla happy path + kluczowych brzegów”).\n- Granice wydajności: optymalizuj tylko przy dowodach (wolne endpointy, gorąca pętla, zmierzone regresje).\n\n### Generuj → recenzuj → mierz → doskonal\n\n1) Opisz funkcjonalność i ograniczenia (wejścia, wyjścia, niezmienniki, przypadki błędów).\n\n2) Poproś AI o prostą implementację najpierw wraz z testami.\n\n3) Recenzuj pod kątem czytelności przed sprytem. Jeśli trudno to streścić w kilku zdaniach, prawdopodobnie jest zbyt skomplikowane.\n\n4) Mierz tylko relewantne części. Uruchom szybki benchmark lub dodaj lekkie timingi wokół podejrzanych wąskich gardeł.\n\n5) Doprecyzowuj krótkimi promptami. Zamiast „przyspiesz”, poproś „zmniejsz alokacje w tej pętli, zachowując strukturę funkcji”.\n\n### Co robić, a czego unikać\n\n- Rób: proś o małe, kompozycyjne funkcje z jasnymi nazwami.\n- Rób: wymagaj przykładów wejść/wyjść i testów w tej samej odpowiedzi.\n- Rób: proś o komentarze tylko tam, gdzie „dlaczego” nie jest oczywiste.\n- Nie rób: akceptuj mikrooptymalizacje bez pomiaru.\n- Nie rób: pozwól na „magiczne” helpery lub abstrakcje, które nie są używane gdzie indziej.\n- Nie rób: merguj kod AI, którego nikt w zespole nie potrafi swobodnie modyfikować.\n\n### Szablon promptu do ponownego użycia (kopiuj/wklej)\n\n\nYou are generating application logic for our codebase.\n\nFeature:\n- Goal:\n- Inputs:\n- Outputs:\n- Business rules / invariants:\n- Error cases:\n- Expected scale (typical and worst-case):\n\nConstraints:\n- Keep functions small and readable; avoid deep nesting.\n- Naming: use domain terms; no abbreviations.\n- Performance: prioritize clarity; optimize only if you can justify with a measurable reason.\n- Tests: include unit tests for happy path + edge cases.\n\nDeliverables:\n1) Implementation code\n2) Tests\n3) Brief explanation of trade-offs and any performance notes\n\n\nJeśli utrzymasz tę pętlę — generuj, recenzuj, mierz, dopracowuj — otrzymasz kod, który pozostanie zrozumiały, a jednocześnie spełni oczekiwania wydajnościowe.
Startuj od najbardziej czytelnej i poprawnej wersji, a optymalizuj dopiero wtedy, gdy masz dowody (logi, profilowanie, pomiary opóźnień), że to wąskie gardło. W logice aplikacji największe zyski zwykle wynikają z ograniczenia I/O (mniej zapytań do BD/serwisów) zamiast mikrooptymalizacji pętli.
Logika aplikacji to kod wyrażający reguły biznesowe i przepływy (eligibility, ceny, przejścia stanów) — zmienia się często. Infrastruktura to „rury” (połączenia z BD, serwery HTTP, kolejki, logowanie) i ma inne, zwykle stabilniejsze wymagania dot. wydajności i niezawodności.
Ponieważ poprawa jednego celu często wpływa negatywnie na inne:
Równoważenie to wybór, który cel jest najważniejszy dla danego modułu i momentu.
Model przewiduje najbardziej prawdopodobne wzorce z Twojego promptu i przykładów, zamiast rozumować jak inżynier. Najsilniejsze sygnały to:
Jeżeli jesteś nieprecyzyjny, model może „przesadzić” z rozwiązaniami.
Uważaj na:
Jeżeli po jednym przeczytaniu nie potrafisz szybko wytłumaczyć przepływu, poproś model o uproszczenie i jawne przedstawienie kontroli przepływu.
Podaj kryteria akceptacji, non-goals i ograniczenia. Przykładowo:
To zapobiegnie wymyślaniu przez model niechcianej złożoności.
Poproś o dwie wersje:
Dodatkowo wymagaj prostego opisu złożoności i listy przypadków brzegowych, aby ułatwić przegląd.
Stosuj wzorce, które czynią intencję oczywistą:
isEligibleForDiscount) zamiast ogólnikówJeśli helper ma ogólną nazwę, może ukrywać reguły biznesowe.
Skupiaj się na dużych, wyjaśnialnych usprawnieniach:
Jeżeli dodajesz cache/batching/indexing, opisuj reguły unieważniania, rozmiar batcha i zachowanie przy błędach.
Testy to kontrakt. Poproś o nie razem z kodem:
Dobre testy pozwalają bezpiecznie refaktoryzować i optymalizować gorące ścieżki.