Przepisałem działającą aplikację. I zgubiłem funkcję, o której nikt nie wiedział
· Nie jednym promptem · odcinek 3
Przez pół roku Zakupomat był aplikacją w przeglądarce. Nasza, domowa, sprawdzona w boju. Marta uzupełnia listę, ja robię zakupy, wszystko działa.
Latem zdecydowałem, że chcę się nią podzielić. I szybko okazało się, że PWA to za mało.
Dlaczego PWA nie wystarczyła
Na papierze PWA brzmi świetnie - jeden kod, działa wszędzie, nie trzeba przechodzić przez żadne sklepy (i płacić niemało za konta deweloperskie!). W praktyce, kiedy chcesz, żeby z aplikacji korzystali nie tylko znajomi, którym sam ją uruchomisz, wychodzą cztery rzeczy:
- Ludzie szukają aplikacji w sklepie. "Wejdź na stronę i dodaj do ekranu głównego" to - jak się okazało - instrukcja, na której odpada większość osób ;-)
- Powiadomienia. Na telefonach z przeglądarki działają... ale tak sobie.
- Aparat. Chciałem, żeby do rodziny dało się dołączyć, skanując kod QR z telefonu drugiej osoby (miało nie być maila, a wygenerowany kod rodziny wcale nie jest taki krótki, a samodzielnie wybrany ktoś inny może odgadnąć i zmodyfikować nam listę). Z przeglądarki działało to zawsze gorzej niż w natywnej aplikacji.
- Prestiż. Ludzie postrzegają aplikacje ze sklepów jako bardziej profesjonalne i zdecydowanie bardziej im ufają (szczególnie ludzie z iPhone'ami).
Nie ma rady - trzeba mieć aplikację. My z Martą mamy iPhone'y, więc zastanawiałem się, czy nie ograniczyć się do App Store, ale w Polsce - gdzie zaczynaliśmy - to Android ma niemal 70% rynku telefonów! Czyli robię na oba. Pytanie brzmiało: jak, skoro Zakupomat rozwijam sam i robię to po godzinach?
Trzy opcje
- Zostać przy PWA i pogodzić się z ograniczeniami. Najtaniej, ale bez sklepów :-(
- Dwie natywne aplikacje - osobno Swift na iOS i Kotlin z Compose na Androida. Najbardziej "po bożemu", ale ten sam kod pisany 2 razy. Niby agenty dobrze sobie z tym radzą, ale to jednak dwie nieco różne aplikacje, wymagające testów i uwagi. Przy jednej osobie - odpada, szczególnie że moja znajomość Swifta jest jedynie przelotna ;-)
- Rozwiązanie wieloplatformowe - jeden kod logiki i jeden kod interfejsu na obie platformy. Kotlin Multiplatform + Compose Multiplatform, Flutter, React Native i takie wynalazki jak .NET MAUI. Języka Dart (z Fluttera) nie znam, .NET MAUI ma fatalne wsparcie w AI i do tego to rozwiązanie od Microsoftu ;-), więc wybór potencjalnie miedzy pozostałymi dwoma.
Wybrałem trzecią z wariantem KMP+CMP (szczegóły wyboru może kiedy indziej). I to był moment, w którym naprawdę poczułem, że zasady gry się zmieniły.
4 lipca
Całą migrację zrobił świeżo wydany (po zawirowaniach) model Claude Fable, który limity wciągał jak Reksio szynkę! Jeden commit: 65 plików, około 4 tysięcy linii kodu i 56 testów. Tego samego dnia nowy kod dostał własne repozytorium.
A potem już poszło. Tydzień później, 12 lipca, jednego dnia powstało sześć kolejnych wersji - zaproszenia kodem QR, skaner na ekranie logowania, kolejka zmian, która przeżywa brak sieci i zamknięcie aplikacji. Wieczorem aplikacja poszła do App Store - po raz pierwszy! (Co było dalej, opowiadałem w poprzednim odcinku ;-))
Brzmi jak bajka. I prawie była.
Funkcja, o której nikt nie wiedział
W starej wersji była drobna rzecz. Jeśli na liście zakupów wpisałeś ilość przy produkcie, którego jeszcze nie zaznaczyłeś, aplikacja sama go zaznaczała. Logiczne - skoro wpisujesz "3", to znaczy, że chcesz ten produkt kupić.
W nowej wersji wpisana ilość po prostu... znikała. Produkt zostawał niezaznaczony, a Twoje "3" przepadało.
Nikt tego nie zauważył przy migracji. Nikt tego nie zauważył przez kolejne tygodnie. Wyszło dopiero wtedy, gdy Marta zgłosiła, że coś jest "dziwnie".
Dlaczego to zginęło
Bo nikt nie wiedział, że ta funkcja istnieje. Nie było jej w żadnym opisie, w żadnej liście funkcji, w żadnym teście. Żyła wyłącznie w kodzie obsługi jednego pola i w przyzwyczajeniach ludzi.
A zgodność nowej wersji ze starą sprawdzałem "na oko" - przechodząc po ekranach. Tylko że takie zachowanie nie jest widoczne na ekranie. Ono dzieje się dopiero w interakcji: co się stanie, kiedy wyjdziesz z pola, kiedy zatwierdzisz klawiaturą, kiedy wpiszesz coś w złej kolejności.
I tu jest pułapka, która z agentami AI robi się jeszcze większa. Agent przepisze Ci aplikację w jeden dzień. Ale przepisze to, co mu pokażesz albo co sam znajdzie. Jeśli nigdzie nie jest zapisane, że pole ilości ma zaznaczać produkt, to nikt - ani człowiek, ani agent - nie ma z czym porównać nowej wersji.
Im szybciej przepisujesz, tym szybciej gubisz.
25 lipca
25 lipca 2026 to była sobota - dzień tygodnia, w którym zakupy z Zakupomatem robi najwięcej rodzin. Rano tego dnia również Marta wyklikiwała produkty do kupienia i zauważyła "coś dziwnego". Pokazała mi to i od razu wiedziałem, co się stało. Poprawka była gotowa jeszcze tego samego dnia.
Ale ważniejsze jest coś innego. Tego samego dnia powstał brain projektu - pamięć, którą Claude czyta na początku każdej sesji. Decyzje, lekcje, zasady pracy. I mapa funkcji - lista wszystkiego, co aplikacja umie, z kolumną, która mówi, czy dana funkcja ma test. Audyt brainu wyłapuje funkcje, które są w kodzie, a nie ma ich w mapie. Przydało się szybko, gdy po fali zmian w aplikacjach mobilnych przyszedł czas na dociągnięcie PWA (nadal jest i robi robotę na desktopie).
Lekcja w brainie ma tytuł, który mówi wszystko: "Migracja bez brainu gubi funkcje po cichu".
I uczciwie - nie mam dziś pełnej listy "stara wersja umiała X, nowa nie". Więc jeśli coś jeszcze zginęło, dowiem się o tym tak samo jak za pierwszym razem - od użytkowników, którzy jeszcze pamiętają PWA. Mapa funkcji chroni przyszłe zmiany. Przeszłości już nie naprawi.
Co to znaczy dla Twojego zespołu
Każdy system, który ma kilka lat, ma funkcje, o których nie wie lub nie pamięta nikt w zespole. Żyją w kodzie obsługi jakiegoś pola, w wyjątku dodanym na prośbę jednego klienta, w obejściu jakiegoś procesu operacyjnego, w przyzwyczajeniach użytkowników. Przy migracji albo dużym refaktorze giną jako pierwsze - i wychodzą miesiącami, pojedynczo, jako "dziwne zachowania".
Agenty AI sprawiają, że przepisanie systemu jest dziś szybsze niż kiedykolwiek. Widziałem już wielkie systemy przepisywane na zupełnie inną technologię - taką, z którą agentom AI pracuje się dużo lepiej - w mniej niż 24h.
Tym bardziej warto zacząć od spisu tego, co system naprawdę robi. Dobra wiadomość - agent może też pomóc ten spis odtworzyć, zanim zacznie cokolwiek przepisywać. Niestety, im gorsza jest nasza dokumentacja i kod (i testy), tym dłużej ten proces trwa, m.in. poprzez nadmiarowe logowanie i zbieranie akcji wykonywanych przez użytkowników, czy powrót do obserwowania, jak z produktem pracują.
Jest jeszcze jedna "rzecz", którą warto wziąć pod uwagę przy migracji - zespół deweloperski! To, że stosunkowo łatwo możemy przepisać system, czy aplikację, na inną technologię, nie oznacza, że nasz zespół jest od razu gotowy na jej dalszy rozwój i utrzymanie. Rzadko kiedy zespół zna obie technologie. Zmieniając zespół, możemy natomiast stracić dużą część wiedzy domenowej lub świetnych, zaangażowanych ludzi, pasujących do kultury naszej firmy.
W ANSLAN zaczynamy właśnie od spisu tego, co system naprawdę robi: odtwarzamy wiedzę o systemie i zapisujemy ją tak, żeby korzystali z niej i ludzie, i agenty AI. Dopiero potem ruszamy z migracją.
A sam Zakupomat, już z działającym polem ilości, możesz wziąć i używać: zakupomat.app. Na zawsze za darmo, bez reklam, bez sprzedaży danych i bez abonamentu. Android, iPhone i przeglądarka.
Do zobaczenia za tydzień :-)