Jedna baza kodu generowana przez AI dla aplikacji webowych, mobilnych i API
Zobacz, jak jedna baza kodu generowana przez AI może napędzać aplikacje webowe, mobilne i API dzięki współdzielonej logice, spójnym modelom danych i bezpieczniejszym wydaniom.

Co oznacza jedna baza kodu generowana przez AI
„Jedna baza kodu” rzadko oznacza jeden UI działający wszędzie. W praktyce zwykle chodzi o jedno repozytorium i jeden zestaw wspólnych reguł — z oddzielnymi powierzchniami dostarczania (aplikacja webowa, aplikacja mobilna, API), które wszystkie opierają się na tych samych decyzjach biznesowych.
Wspólna logika vs. wspólne UI
Dobrym modelem mentalnym jest współdzielenie części, które nigdy nie powinny się rozjechać:
- Reguły domeny: obliczenia, sprawdzenia kwalifikowalności, cenniki, workflowy, niezmienniki.
- Przypadki użycia: „utwórz zamówienie”, „anuluj subskrypcję”, „wystaw zwrot” itd.
- Kontrakty danych: kształty request/response, reguły walidacji, kody błędów.
Tymczasem zwykle nie współdzielisz warstwy UI w całości. Web i mobile mają różne wzorce nawigacji, oczekiwania dotyczące dostępności, ograniczenia wydajności i możliwości platformy. Wspólne UI może być opłacalne w niektórych przypadkach, ale to nie jest definicja „jednej bazy kodu”.
Co AI zmienia (a co pozostaje bez zmian)
Kod generowany przez AI może znacząco przyspieszyć:
- inicjowanie projektów (struktury folderów, skrypty build, podstawowe komponenty)
- generowanie endpointów CRUD i klientóww
- tworzenie testów i fixture’ów na podstawie przykładów
Ale AI nie wygeneruje automatycznie spójnej architektury. Bez jasnych granic ma tendencję do duplikowania logiki między aplikacjami, mieszania odpowiedzialności (UI wywołujące bezpośrednio kod bazy danych) i tworzenia „prawie takich samych” walidacji w wielu miejscach. Wartość pojawia się, gdy najpierw definiujesz strukturę, a potem używasz AI do wypełniania powtarzalnych części.
Wyniki, do których warto dążyć
Jedna baza kodu wspierana przez AI jest sukcesem, gdy zapewnia:
- Spójność: web, mobile i API egzekwują te same reguły.
- Szybkość: nowe funkcje piszesz raz, potem trafiają wszędzie.
- Utrzymywalność: zmiany są lokalizowane, przeglądane, testowane i wydawane przewidywalnie.
Cele i ograniczenia dla dostarczania web, mobile i API
Jedna baza kodu działa tylko wtedy, kiedy jesteś jasny co do tego, co musi osiągnąć — i czego nie powinieneś próbować ujednolicać. Web, mobile i API obsługują różne grupy użytkowników i wzorce użycia, nawet gdy dzielą te same reguły biznesowe.
Kogo obsługujesz (i jak)
Większość produktów ma przynajmniej trzy „wejścia”:
- Użytkownicy webowi (klienci, administratorzy, zespoły wsparcia), którzy oczekują szybkiej nawigacji, dostępności i łatwych aktualizacji.
- Użytkownicy mobilni, którzy oczekują natywnych interakcji, wsparcia przy słabym zasięgu i efektywnego użycia baterii/danych.
- Integracje zewnętrzne (partnerzy, systemy wewnętrzne, narzędzia automatyzacji), które polegają na stabilnych API, jasnych kontraktach i przewidywalnym obsługiwaniu błędów.
Cel to spójność w zachowaniu (reguły, uprawnienia, obliczenia) — nie identyczne doświadczenia.
Niecele: nie wymuszaj identycznego UX
Częstym błędem jest traktowanie „jednej bazy kodu” jak „jednego UI”. To zwykle daje webopodobne mobile lub mobilopodobny web — oba frustrujące.
Zamiast tego celuj w:
- współdzieloną logikę domeny i walidację
- wspólne modele danych i kontrakty API
- specyficzny dla platformy projekt prezentacji i interakcji
Kluczowe ograniczenia do zaprojektowania wcześnie
Tryb offline: Mobile często potrzebuje odczytu (a czasem zapisu) bez sieci. To wymaga lokalnego magazynu, strategii synchronizacji, obsługi konfliktów i jasnych reguł „źródła prawdy”.
Wydajność: Web dba o rozmiar paczki i czas do interaktywności; mobile o czas uruchomienia i efektywność sieciową; API o opóźnienia i przepustowość. Współdzielenie kodu nie powinno oznaczać wysyłania niepotrzebnych modułów do każdego klienta.
Bezpieczeństwo i zgodność: Uwierzytelnianie, autoryzacja, ścieżki audytu, szyfrowanie i przechowywanie danych muszą być spójne. Jeśli działasz w regulowanej przestrzeni, uwzględnij wymagania (logi, zgody, zasada najmniejszych uprawnień) od początku, nie jako łatki.
Architektura referencyjna: warstwy i odpowiedzialności
Jedna baza kodu działa najlepiej, gdy jest zorganizowana w jasne warstwy z restrykcyjnymi odpowiedzialnościami. Taka struktura ułatwia też przegląd, testowanie i podmianę generowanego przez AI kodu bez łamania niezwiązanych fragmentów.
Przepływ wysokiego poziomu
Oto podstawowy kształt, do którego większość zespołów dąży:
Clients (Web / Mobile / Partners)
↓
API Layer
↓
Domain Layer
↓
Data Sources (DB / Cache / External APIs)
Kluczowa idea: interfejsy użytkownika i szczegóły transportu siedzą na krawędziach, podczas gdy reguły biznesowe są w centrum.
Co jest współdzielone
„Core do współdzielenia” to wszystko, co powinno zachowywać się tak samo wszędzie:
- Domena (logika biznesowa): reguły cenowe, sprawdzenia kwalifikowalności, przejścia stanów zamówienia itd.
- Walidacja: reguły wejścia i komunikaty o błędach mapowane na spójne kody błędów.
- Sieć + schematy: typy request/response, serializacja i testy kontraktowe.
Gdy AI generuje nowe funkcje, najlepszy wynik to: zaktualizować reguły domeny raz, a wszystkie klienty odniosą korzyść automatycznie.
Co powinno pozostać inne
Niektóre elementy są kosztowne (lub ryzykowne) do wymuszenia w wspólnym abstrakcie:
- Komponenty UI: systemy projektowe web vs. natywne kontrolki.
- Nawigacja i przepływy użytkownika: routing przeglądarki vs. stosy nawigacji mobilnej.
- Możliwości urządzenia: powiadomienia push, biometryka, aparat, magazyn offline.
Praktyczna zasada: jeśli użytkownik to widzi lub system operacyjny może to zepsuć, trzymaj to specyficzne dla aplikacji. Jeśli to decyzja biznesowa — trzymaj ją w domenie.
Odpowiedzialności według warstwy
- Warstwa API: uwierzytelnianie, limity, mapowanie HTTP/GraphQL na komendy domenowe.
- Warstwa domeny: czyste reguły i przypadki użycia, minimalne zależności.
- Źródła danych: bazy i serwisy zewnętrzne za interfejsami, aby implementacje można było zmienić bez przepisywania logiki biznesowej.
Wspólna warstwa domeny (logika biznesowa)
Wspólna warstwa domeny powinna być „nudna” w najlepszym znaczeniu: przewidywalna, testowalna i wielokrotnego użytku. Jeśli AI pomaga budować system, to właśnie w tej warstwie kotwiczysz sens projektu — dzięki temu ekrany web, przepływy mobilne i endpointy API odzwierciedlają te same reguły.
Zacznij od rzeczowników i czasowników
Zdefiniuj kluczowe pojęcia produktu jako encje (obiekty posiadające tożsamość w czasie, np. Account, Order, Subscription) i value objects (określone wartością, np. Money, EmailAddress, DateRange). Następnie uchwyć zachowania jako przypadki użycia (czasem nazywane usługami aplikacyjnymi): „Utwórz zamówienie”, „Anuluj subskrypcję”, „Zmień email”.
Ta struktura utrzymuje domenę zrozumiałą także dla osób nietechnicznych: rzeczowniki opisują, co istnieje, czasowniki — co system robi.
Trzymaj reguły biznesowe niezależne od UI
Logika biznesowa nie powinna wiedzieć, czy jest wywoływana przez stuknięcie przycisku, wysłanie formularza webowego czy żądanie API. Praktycznie oznacza to:
- Brak importów frameworków (żadne kontrolery web, widoki mobilne ani adnotacje ORM w kodzie domeny)
- Brak tekstów UI (lepsze są kody błędów niż hardkodowane wiadomości)
- Brak założeń sieciowych (domena nie powinna „wołać API”; powinna wyrażać reguły)
Gdy AI generuje kod, łatwo o utratę tej separacji — modele bywają przeładowane rzeczami z UI. Traktuj to jako sygnał do refaktoru.
Jedne reguły walidacji wszędzie
Walidacja to miejsce, gdzie produkty najczęściej się rozjeżdżają: web pozwala coś, co API odrzuca, albo mobile waliduje inaczej. Umieść spójną walidację w warstwie domeny (lub współdzielonym module), aby wszystkie powierzchnie egzekwowały te same reguły.
Przykłady:
EmailAddresswaliduje format raz i jest używany we wszystkich klientachMoneyzapobiega ujemnym sumom, skąd by wartość nie pochodziła- Przypadki użycia egzekwują reguły między-pól (np. „data końcowa po dacie początkowej”)
Przy dobrym wykonaniu warstwa API staje się tłumaczem, a web/mobile prezenterami — podczas gdy domena pozostaje jedynym źródłem prawdy.
Warstwa API: kontrakty, które napędzają resztę
Warstwa API jest „publicznym obliczem” twojego systemu — i w jednej bazie kodu generowanej przez AI powinna być częścią, która kotwiczy wszystko inne. Gdy kontrakt jest jasny, web, mobile, a nawet serwisy wewnętrzne można generować i weryfikować względem tego samego źródła prawdy.
Zacznij od kontraktu API jako pierwszego kroku
Zdefiniuj kontrakt zanim wygenerujesz handlery czy powiązania UI:
- Endpointy i zasoby: spójne rzeczowniki (np.
/users,/orders/{id}), przewidywalne filtrowanie i sortowanie. - Błędy: stabilny kształt błędu (code, message, details) z udokumentowanym użyciem statusów HTTP.
- Paginacja: wybierz podejście (cursor-based często najłatwiejsze do ewolucji) i ustandaryzuj pola odpowiedzi.
- Wersjonowanie: zdecyduj wcześnie (ścieżka jak
/v1/...lub nagłówki) i udokumentuj zasady deprecjacji.
Generuj typy i klienty z jednego schematu
Użyj OpenAPI (lub narzędzia schema-first jak GraphQL SDL) jako artefaktu kanonicznego. Z tego generuj:
- Szkielety serwera (trasy, walidacja)
- Typowane klienty dla web i mobile
- Współdzielone modele request/response, które zmniejszają dryf
To ma znaczenie przy kodzie generowanym przez AI: model może szybko tworzyć dużo kodu, ale schemat utrzymuje go w zgodzie.
Reguły spójności, które zapobiegają subtelnych awariom
Ustal kilka niepodważalnych zasad:
- Nazewnictwo:
snake_caselubcamelCase, nie oba; dopasowanie między JSON a generowanymi typami. - Kody statusu: 200/201/204 dla sukcesu, 400 dla walidacji, 401/403 dla auth, 409 dla konfliktów.
- Idempotencja: wymagaj
Idempotency-Keydla operacji ryzykownych (płatności, tworzenie zamówień) i zdefiniuj zachowanie przy retry.
Traktuj kontrakt API jak produkt. Gdy jest stabilny, wszystko inne łatwiej generować, testować i wdrażać.
Aplikacja web: integrowanie współdzielonej logiki bez sprzęgania
Aplikacja web dużo zyskuje na współdzielenie logiki biznesowej — i dużo traci, gdy ta logika splata się z UI. Klucz to traktować współdzieloną warstwę domeny jak „headless” silnik: zna reguły, walidacje i workflowy, ale nic o komponentach, trasach czy API przeglądarki.
Wybory renderowania: SSR vs CSR (i dlaczego to ważne)
Jeśli używasz SSR (server-side rendering), współdzielony kod musi być bezpieczny do uruchomienia po stronie serwera: bez bezpośrednich odwołań do window, document czy storage przeglądarki. To dobry forcing function: trzymaj zachowania zależne od przeglądarki w cienkiej warstwie adaptera web.
Przy CSR (client-side rendering) masz więcej swobody, ale ta sama dyscyplina się opłaca. Projekty CSR często „przypadkowo” importują kod UI do modułów domeny, bo wszystko działa w przeglądarce — aż do momentu, gdy dodasz SSR, edge rendering lub testy uruchamiane w Node.
Praktyczna zasada: moduły współdzielone powinny być deterministyczne i agnostyczne względem środowiska; wszystko, co dotyka ciasteczek, localStorage lub URL, należy do warstwy web.
Granice stanu: stan domeny vs stan UI
Wspólna logika może ujawniać stan domeny (np. sumy zamówień, flagi kwalifikacyjne, pola pochodne) przez zwykłe obiekty i funkcje czyste. Aplikacja web powinna posiadać stan UI: spinnery, fokus formularza, animacje optymistyczne, widoczność modalów.
To pozwala zmieniać biblioteki stanu (React/Vue) bez przepisywania reguł biznesowych.
Specyficzne dla webu kwestie, które należy izolować
Warstwa web powinna obsługiwać:
- Dostępność (semantyczne znaczniki, nawigacja klawiaturą, ARIA)
- Routing (struktura URL, deep links, przekierowania serwera)
- Magazynowanie w przeglądarce (ciasteczka/sesja,
localStorage, cache)
Traktuj aplikację web jako adapter, który tłumaczy interakcje użytkownika na komendy domenowe i wynik domeny na dostępne ekrany.
Aplikacja mobilna: współdzielenie logiki z natywnymi możliwościami
Aplikacja mobilna najbardziej zyskuje na współdzielonej warstwie domeny: reguły cen, walidacja i workflowy powinny działać tak samo jak w webie i API. UI mobilne staje się „powłoką” wokół tej logiki — zoptymalizowaną pod dotyk, przerwane połączenia i funkcje urządzenia.
Wzorce platformowe, na które warto zaprojektować
Nawet przy współdzielonej logice mobile ma wzorce, które rzadko mapują 1:1 na web:
- Nawigacja: modeluj stan nawigacji w warstwie aplikacji (ekrany, zakładki, modalne), a decyzje domenowe trzymaj w wspólnym kodzie (np. „użytkownik musi potwierdzić email przed checkoutem”).
- Zadania w tle: traktuj sync, uploady i odświeżanie jako zadania z ograniczeniem czasu i możliwością wznowienia.
- Powiadomienia push: parsuj payload w warstwie aplikacji, potem przekazuj do wspólnej logiki.
- Deep links: routuj linki w warstwie aplikacji, używaj wspólnej logiki do walidacji uprawnień i pobrania danych.
Offline-first: cache, sync i strategia konfliktów
Jeśli spodziewasz się realnego użycia mobilnego, zakładaj tryb offline:
- Cache’uj modele odczytu lokalnie (key-value lub SQLite) z jasną polityką świeżości.
- Kolejkkuj zapisy jako intencje/wydarzenia (np. „utwórz szkic zamówienia”), potem synchronizuj online.
- Zdefiniuj reguły konfliktów wcześniej (last-write-wins, server-authoritative merge lub rozwiązywanie przez użytkownika).
- Implementuj retry z backoffem i idempotency keys, aby API bezpiecznie przyjmowało duplikaty.
Sprawy specyficzne dla mobilnego
- Wielkość aplikacji: utrzymuj warstwę współdzieloną modułową, by wysyłać tylko to, czego aplikacja potrzebuje.
- Bateria/dane: grupuj wywołania sieciowe i unikaj agresywnego polling.
- Uprawnienia: żądaj tylko wtedy, gdy potrzeba (aparat, lokalizacja, kontakty) i trzymaj sprawdzanie uprawnień poza kodem domeny, żeby polityki mogły się różnić per platforma.
Modele danych, auth i uprawnienia we wszystkich powierzchniach
„Jedna baza kodu” szybko się rozpada, jeśli web, mobile i API każde wymyślą własne kształty danych i zasady bezpieczeństwa. Naprawa to traktować modele, uwierzytelnianie i autoryzację jako wspólne decyzje produktu i zakodować je raz.
Jedno źródło prawdy dla modeli danych
Wybierz jedno miejsce, gdzie modele żyją i niech wszystko inne od niego pochodzi. Typowe opcje:
- Schema-first: definiuj encje i reguły walidacji w plikach schematów (OpenAPI/JSON Schema), potem generuj typy dla API, web i mobile.
- Wspólne moduły: trzymaj typy modeli i walidatory w współdzielonym pakiecie (często moduł „domain”), który importują wszystkie aplikacje.
- Hybryda: pliki schematów dla kontraktów zewnętrznych, wspólne moduły dla wewnętrznych reguł domeny.
Klucz to nie narzędzie — lecz spójność. Jeśli OrderStatus ma pięć wartości w jednym kliencie, a sześć w drugim, kod generowany przez AI chętnie skompiluje i nadal wyśle bugi.
Uwierzytelnianie: sesje, tokeny i bezpieczne przechowywanie
Auth powinien być koncepcyjnie jednolity, ale mechanika różna per powierzchnia:
- Web: często preferuje sesje oparte na ciasteczkach (dobre zabezpieczenia CSRF, proste przechowywanie).
- Mobile i klienci zewnętrzni potrzebują zwykle auth opartego na tokenach (access + refresh token).
Zaprojektuj jeden flow: logowanie → krótkożyjący access → odświeżanie w razie potrzeby → wylogowanie unieważniające stan po stronie serwera. Na mobile trzymaj tajne klucze w bezpiecznym magazynie (Keychain/Keystore), nie w preferencjach. Na web preferuj httpOnly cookies, żeby tokeny nie były dostępne w JS.
Autoryzacja: centralne reguły, egzekwowane w API
Uprawnienia powinny być definiowane raz — najlepiej blisko reguł biznesowych — i stosowane wszędzie.
- Centralizuj sprawdzenia w domenie (np.
canApproveInvoice(user, invoice)). - Egzekwuj je w API dla realnego bezpieczeństwa.
- Odwzorowuj je w UI tylko po to, by ukrywać/wyłączać akcje, nie do ochrony danych.
To zapobiega „działa na mobile, nie działa na web” i daje generacji AI jasny, testowalny kontrakt kto co może robić.
Strategia budowy, wydawania i wdrażania
Zunifikowana baza kodu pozostaje zunifikowana tylko wtedy, gdy buildy i wydania są przewidywalne. Celem jest pozwolić zespołom wdrażać API, web i mobile niezależnie — bez rozgałęzień logiki czy „special casingu” środowisk.
Monorepo vs multi-repo
Monorepo (jedno repo, wiele pakietów/aplikacji) zwykle lepiej pasuje do jednej bazy kodu, bo współdzielona logika domeny, kontrakty API i klienty ewoluują razem. Masz atomiczne zmiany (jeden PR aktualizuje kontrakt i wszystkich konsumentów) i prostsze refaktory.
Multi-repo nadal może być zunifikowane, ale kosztuje koordynację: wersjonowanie współdzielonych pakietów, publikowanie artefaktów i synchronizację breaking changes. Wybierz multi-repo tylko wtedy, gdy granice organizacyjne, reguły bezpieczeństwa lub skala czynią monorepo niepraktycznym.
Cele budowania i artefakty
Traktuj każdą powierzchnię jako osobny target buildu, który konsumuje współdzielane pakiety:
- Artefakt serwisu API: obraz kontenera lub bundle serverless z pakietu API.
- Web bundle: statyczne assety + runtime serwera (jeśli SSR) z pakietu web.
- Buildy mobilne: Android (AAB/APK) i iOS (IPA) w natywnych pipeline’ach, importujące współdzieloną logikę jako zależność.
Utrzymuj buildy deterministyczne (lockfile, przypięte toolchainy, deterministyczne buildy).
CI/CD i separacja środowisk
Typowy pipeline: lint → typecheck → testy jednostkowe → testy kontraktowe → build → skan bezpieczeństwa → deploy.
Oddziel konfigurację od kodu: zmienne środowiskowe i sekrety w CI/CD i managerze sekretów, nie w repo. Używaj nakładek środowiskowych (dev/stage/prod), by ten sam artefakt mógł być promowany między środowiskami bez przebudowy — zwłaszcza dla API i runtime web.
Testowanie i bramki jakości dla współdzielonego kodu
Kiedy web, mobile i API wypływają z tej samej bazy kodu, testy przestają być „kolejnym checkboxem” a stają się mechanizmem zapobiegającym zablokowaniu trzech produktów jedną zmianą. Celem jest wykrywać problemy tam, gdzie ich naprawa jest najtańsza, i blokować ryzykowne zmiany przed dotarciem do użytkowników.
Praktyczna piramida testów dla współdzielonej bazy kodu
Zacznij od warstwy domeny (logiki biznesowej), bo jest najbardziej wykorzystywana i najłatwiejsza do testowania bez wolnej infrastruktury.
- Testy jednostkowe (warstwa domeny): waliduj reguły jak ceny, kwalifikowalność, decyzje uprawnień, przejścia stanów i przypadki brzegowe. Powinny być szybkie i stanowić większość suite’u.
- Testy integracyjne (warstwa API): sprawdź end-to-end serializację, walidację, auth i dostęp do danych. Skup je na krytycznych przepływach, nie na każdym rogu.
- Testy UI (per klient): kilka wysokowartościowych sprawdzeń dla web i mobile, potwierdzających kluczowe ścieżki (logowanie, checkout, wysłanie formularza). Są wolniejsze, więc traktuj je jak „czujniki dymu”, a nie wyczerpujący dowód.
Taka struktura daje największą pewność w współdzielonej logice, a jednocześnie łapie problemy przy łączeniu warstw.
Testy kontraktowe, aby klient i API pozostały w zgodzie
Nawet w monorepo łatwo zmienić API w sposób, który się kompiluje, ale psuje UX. Testy kontraktowe zapobiegają cichym dryfom.
- Kontrakty API→klient: zablokuj kształty request/response, formaty błędów i statusy. Jeśli API doda nowe wymagane pole lub zmieni wartość enum, testy kontraktowe nie przejdą przed merge.
- Schemat jako bramka: jeśli publikujesz OpenAPI/GraphQL, traktuj zmiany schematu jako artefakty do przeglądu. Breaking changes wymagają wyraźnej akceptacji i planu migracji.
Bramki jakości chroniące wydania
Dobre testy są ważne, ale równie ważne są zasady wokół nich.
- Gates PR: wymagaj przejścia testów jednostkowych i integracyjnych, lintingu/formatowania i minimalnego coverage dla warstwy domeny.
- Feature flags: wprowadzaj kod bezpiecznie, ukrywając niedokończone zachowania za flagami, które można włączyć per środowisko lub grupa użytkowników.
- Stopniowe rollouty: najpierw wewnętrzni użytkownicy, potem mały % ruchu produkcyjnego, potem wszyscy.
- Plan rollbacku: traktuj rollback jako równorzędny wynik — wersjonowane wydania, migracje bazy odwracalne (lub bezpieczne do kolejnych migracji) i jasne kryteria „zatrzymaj linię”.
Z tymi bramkami zmiany generowane przez AI mogą być częste, ale nie kruche.
Jak korzystać z AI, nie tracąc kontroli nad architekturą
AI może przyspieszyć pracę nad jedną bazą kodu, ale tylko jeśli traktujesz je jak szybkiego młodszego inżyniera: doskonałe do szkiców, niebezpieczne do bezrefleksyjnego mergowania. Cel: używać AI dla szybkości, a ludzi pozostawić odpowiedzialnymi za architekturę, kontrakty i długoterminową spójność.
Gdzie AI pomaga najbardziej (i niskie ryzyko)
Używaj AI do generowania „pierwszych wersji”, które i tak byś napisał mechanicznie:
- szkielety projektów (foldery, boilerplate, moduły)
- dokumentacja API i przykłady na podstawie kontraktów
- zestawy testów (testy jednostkowe domeny, testy kontraktowe endpointów)
- migracje i skrypty seedujące dane
- powtarzalne refaktory (zmiana nazw, rozdzielanie modułów), po zdefiniowaniu planu
Dobra zasada: pozwól AI wygenerować kod, który łatwo zweryfikować przez czytanie lub uruchamianie testów, nie kod, który cicho zmienia znaczenie biznesowe.
Zabezpieczenia chroniące architekturę
Output AI powinien być ograniczony przez explicite reguły, nie „odczucia”. Umieść te reguły tam, gdzie jest kod:
- Standardy kodowania: linters/formatters, reguły nazewnictwa i zakazy typu „UI nie ma bezpośredniego dostępu do DB”.
- Reguły architektoniczne: granice zależności (np. warstwa domeny nie może importować API/web/mobile), wymuszane narzędziami lub prostymi checkami buildu.
- Checklist PR: „Zmieniono kontrakt? Zaktualizuj OpenAPI + klienty + testy.” „Nowa reguła domeny? Dodaj testy domeny.”
Jeśli AI zasugeruje skrót łamiący granice, odpowiedź to „nie”, nawet jeśli się kompiluje.
Zarządzanie: audytowalność pracy AI
Ryzyko to nie tylko zły kod — to nieodnotowane decyzje. Zadbaj o ślad audytu:
- zapisuj kluczowe prompt-y i odpowiedzi powiązane z ticketami/PR
- rejestruj decyzje architektoniczne (ADR) dla zmian kontraktów, modelu auth czy nowych konceptów domenowych
- wymagaj, aby zmiany API były jawne: wersjonowane, udokumentowane i zabezpieczone testami kontraktowymi
AI jest najbardziej użyteczne, gdy jego efekty są powtarzalne: zespół widzi dlaczego coś wygenerowano, może to zweryfikować i bezpiecznie wygenerować ponownie, gdy wymagania się zmienią.
Uwaga narzędziowa: AI, które przestrzega granic
Jeśli wdrażasz AI wspomagające rozwój systemowy (web + API + mobile), najważniejszą „funkcją” nie jest surowa prędkość generowania — tylko umiejętność zachowania zgodności z kontraktami i warstwami.
Na przykład Koder.ai to platforma vibe-coding, która pomaga zespołom budować web, serwer i aplikacje mobilne przez interfejs czatu — przy jednoczesnym generowaniu realnego, eksportowalnego kodu. W praktyce to użyteczne dla workflow opisanego w tym artykule: możesz zdefiniować kontrakt API i reguły domeny, a potem szybko iterować nad surface'ami React, backendem Go + PostgreSQL i aplikacjami Flutter bez utraty możliwości przeglądu, testów i egzekwowania granic architektury. Funkcje takie jak tryb planowania, snapshoty i rollback dobrze wpisują się w dyscyplinę „generuj → weryfikuj → promuj” w zunifikowanej bazie kodu.
Kiedy nie stosować jednej bazy kodu (i co robić zamiast tego)
Jedna baza kodu może zmniejszyć duplikację, ale nie jest domyślnym „najlepszym” wyborem. W momencie, gdy współdzielony kod zaczyna wymuszać niezręczne UX, spowalniać wydania lub ukrywać różnice platform, spędzisz więcej czasu na negocjacjach architektonicznych niż na dostarczaniu wartości.
Przypadki, gdy oddzielne bazy kodu są lepsze
Oddzielne bazy (albo przynajmniej oddzielne warstwy UI) często mają sens gdy:
- UI jest produktem samym w sobie. Jeśli web i mobile potrzebują fundamentalnie różnych modeli interakcji (gesty, ekrany offline-first, obsługa aparatu, skomplikowane animacje), współdzielenie UI staje się kompromisem.
- Ścisłe ograniczenia platformowe. Zasady App Store, uprawnienia sprzętowe, limity wykonywania w tle czy wymagania dostępnościowe mogą wymagać specyficznych implementacji.
- Różne cykle wydawnicze. Mobile może wypuszczać co miesiąc, web codziennie. Tightly coupled monorepo może zmieniać każdą zmianę w wydarzenie koordynacyjne.
Typowe tryby awarii, na które warto uważać
- Nadmierne współdzielenie UI: „Jeden UI dla wszystkich” daje doświadczenia z najniższego wspólnego mianownika.
- Przeciekające abstrakcje: „Wspólny” moduł nadal ujawnia szczegóły web/mobile (routing, storage, auth tokeny), więc każdy konsument staje się kruchy.
- Dryf wersji: zespoły kopiują kod, by przyspieszyć, potem poprawki trafiają tylko w jedno miejsce.
Lista kontrolna decyzyjna (i co zrobić zamiast tego)
Zadaj sobie pytania przed podjęciem decyzji o jednej bazie kodu:
- Czy logika domeny da się współdzielić czysto, pozostawiając UI natywnym?
- Czy zespoły platformowe potrzebują autonomii w narzędziach, wydaniach i eksperymentach?
- Czy API są wystarczająco stabilne, aby klienci mogli ewoluować niezależnie?
Jeśli widzisz sygnały ostrzegawcze, praktyczną alternatywą jest wspólna domena + kontrakty API, z oddzielnymi aplikacjami web i mobile. Trzymaj współdzielony kod skoncentrowany na regułach biznesowych i walidacji, a każdemu klientowi pozwól mieć własne UX i integracje platformowe.
Jeśli chcesz pomocy w wyborze ścieżki, porównaj opcje na /pricing lub przeglądnij powiązane wzorce architektoniczne na /blog.
Często zadawane pytania
Czy „jedna baza kodu generowana przez AI” oznacza jeden UI działający wszędzie?
Zwykle oznacza to jedno repozytorium i jeden zestaw wspólnych reguł, a nie jedną identyczną aplikację.
W praktyce web, mobile i API współdzielą warstwę domenową (reguły biznesowe, walidacje, przypadki użycia) i często jeden kontrakt API, podczas gdy każda platforma zachowuje własny interfejs i integracje specyficzne dla platformy.
Co powinno być współdzielone między webem, mobile i API — a co nie?
Dziel to, co nie może się różnić:
- Reguły domeny (cenniki, uprawnienia, workflowy, niezmienniki)
- Przypadki użycia (utwórz zamówienie, anuluj subskrypcję, zwróć środki)
- Walidacja i kody błędów
- Schematy/kontrakty API (OpenAPI/GraphQL) i generowane typy
Pozostaw komponenty UI, nawigację oraz integracje z urządzeniem/przeglądarką specyficzne dla platformy.
Co AI zmienia w architekturze, a co się nie zmienia?
AI przyspiesza tworzenie szkieletów i prac powtarzalnych (CRUD, klienty, testy), ale samo nie zbuduje dobrych granic architektonicznych.
Bez świadomej architektury kod generowany przez AI często:
- duplikuje logikę w różnych aplikacjach
- miesza odpowiedzialności (UI odwołujące się bezpośrednio do źródeł danych)
- tworzy nieco różniące się walidacje w wielu miejscach
Używaj AI do wypełniania dobrze zdefiniowanych warstw, nie do wymyślania struktury od zera.
Jaka jest dobra architektura referencyjna dla jednej wspólnej bazy kodu?
Prosty i niezawodny przepływ to:
- Klienci (web/mobile/partnerzy) → warstwa API
- Warstwa API tłumaczy żądania na przypadki użycia domeny
- Domeny wywołują interfejsy źródeł danych (DB/cache/externals)
Dzięki temu reguły biznesowe są scentralizowane, a testowanie i przegląd generowanych przez AI dodatków są łatwiejsze.
Jak zapobiec dryfowi walidacji między webem, mobile i API?
Umieść walidację w jednym miejscu (warstwa domeny lub współdzielony moduł walidacji), a następnie używaj jej we wszystkich klientach.
Praktyczne wzorce:
- waliduj
EmailAddressiMoneytylko raz - egzekwuj reguły między-pól w przypadkach użycia (np. zakresy dat)
- zwracaj stabilne kody błędów (UI mapuje kody na komunikaty)
To zapobiega sytuacjom „web akceptuje, API odrzuca”.
Jak kontrakt API może stać się „źródłem prawdy” dla całego systemu?
Użyj kanonicznego schematu, np. OpenAPI (lub GraphQL SDL) i generuj z niego:
- szkielety serwera i walidację żądań
- typowane klienty dla webu i mobile
- współdzielone modele request/response
Dodaj testy kontraktowe, aby zmiany łamiące schemat nie przeszły w CI.
Co oznacza „offline-first” przy współdzieleniu logiki z aplikacją mobilną?
„Offline-first” oznacza świadome projektowanie trybu offline, nie poleganie na przypadkowym cache’owaniu:
- cacheuj modele odczytu lokalnie z jasną polityką świeżości
- kolejkkuj zapisy jako intencje/wydarzenia i synchronizuj przy online
- zdefiniuj reguły konfliktów (server-authoritative, merge lub rozwiązanie przez użytkownika)
- używaj retry z backoffem i idempotency keys
Przechowywanie offline i logika sync pozostają w warstwie aplikacji mobilnej; reguły biznesowe w warstwie współdzielonej.
Jak powinien działać mechanizm auth i uprawnień między webem, mobile i API?
Upewnij się, że proces wygląda tak samo dla użytkownika, ale mechanika zależy od powierzchni:
- Web: często sesje oparte na ciasteczkach httpOnly
- Mobile/klienci trzecich stron: tokeny (access + refresh) przechowywane w Keychain/Keystore
Reguły autoryzacji definiuj centralnie (np. canApproveInvoice) i egzekwuj w API; UI ma je tylko odzwierciedlać, aby ukryć/wyłączyć akcje.
Jak utrzymać porządek w budowie i wydawaniu w zunifikowanej bazie kodu?
Traktuj każdą powierzchnię jako osobny target budowania, korzystający ze współdzielanych pakietów:
- API: obraz kontenera lub bundle serverless
- Web: statyczne assety + runtime SSR, jeśli potrzeba
- Mobile: natywne buildy iOS/Android importujące współdzieloną logikę
W CI/CD uruchamiaj: lint → typecheck → testy jednostkowe → testy kontraktowe → build → skanowanie bezpieczeństwa → deploy. Trzymaj sekretne dane w managerze sekretów, nie w repozytorium.
Jak używać AI, nie tracąc kontroli nad architekturą?
Używaj AI jak szybkiego młodszego inżyniera: świetny do szkiców, niebezpieczny do bezkrytycznego merge’u.
Dobre praktyki:
- wygeneruj szkielety projektu, testy jednostkowe i przykłady API
- narzuć zasady: linters, ograniczenia zależności (np. domena nie importuje warstwy UI)
- wymagaj testów domeny dla nowych reguł i aktualizacji schematów
- zapisuj ważne prompt-y i decyzje architektoniczne jako ADRy powiązane z PR
Jeśli output AI łamie granice architektury, odrzuć go, nawet jeśli kompiluje.