← Powrót na blog

Dlaczego budujemy ModularPlatform jako solidny fundament, a nie PoC

Większość produktów zaczyna jako proof of concept, który potem latami się odgania. My budujemy modularny fundament zaprojektowany od początku pod niezawodność, rozszerzalność i bez vendor lock-inu. Co to konkretnie oznacza i dlaczego klientowi oszczędza czas i pieniądze.

Większość produktów, przy których w życiu pracowałem, zaczęła jako proof of concept. Ktoś potrzebował szybko pokazać, że pomysł działa, więc powstała mała aplikacja, która to zrobiła. I potem jej nie wyrzucono. Trafiła na produkcję, przyszedł pierwszy klient, drugi, i nagle ten PoC latami się odgania. Dług techniczny, przestoje, vendor lock-in, którego nikt świadomie nie podpisał.

To powstało z tego, co widziałem, jak się psuje. ModularPlatform budujemy odwrotnie: najpierw czysty, gotowy na produkcję fundament, potem na nim funkcjonalność. To wewnętrzny projekt SolutionBox i wciąż jest w toku — piszę „budujemy", nie „mamy gotowe". Ale chcę opisać, dlaczego robimy to w ten sposób, bo ten powód wynika z doświadczenia, nie z marketingu.

Co mi się powtarzało psuło pod rękami

Zacznę od historii, bo ona nadaje sens reszcie.

W TrafinOil robiłem e-fakturację na KSeF — polski państwowy system elektronicznych faktur. Jest asynchroniczny, rate-limited, bywa niedostępny i ma własny stan. Gdy integruje się go naiwnie, powstaje pipeline fire-and-forget: wysyłam fakturę, mam nadzieję, że dotarła, i jadę dalej. Dokładnie tak było tam wcześniej. Forensycznie odtwarzaliśmy potem 15 141 dokumentów, które ta cicha pipeline utraciła. Nikt o tym nie wiedział, bo nic nie zgłaszało błędu — po prostu nigdzie się to nie zapisało.

Przepisałem to na długotrwały stanowy workflow: idempotentny submit, retry z exponential backoff, rate limiting, reconciliacja, potwierdzenie UPO, audit log. Dziś jest to zweryfikowane na produkcji na ponad 40 000 dokumentach, 100 % dostarczonych. Różnica między tymi dwiema wersjami nie polega na tym, że druga jest „lepiej napisana". Polega na tym, że trwałość, idempotencja i obserwowalność były tam od początku, a nie doklejone po incydencie.

To samo widziałem gdzie indziej z innego kąta. Atlas Copco miało pipeline danych SAP, gdzie jeden skrypt SQL urósł do 15 000 linii, a czas wykonania wydłużył się do kilku dni. Refactor na podejście event-driven na Azure Functions skrócił to do ~4 godzin z EU i zmniejszył ten SQL do 3 000 linii, czyli o 80 % mniej. I znowu: wąskim gardłem nie był język ani framework, ale to, że fundament budowano ad hoc i nikt nie zaprojektował go pod to, co nadejdzie.

To jest sedno, które ModularPlatform rozwiązuje. Gdy firma zaczyna każdy produkt od zera, powtarzalnie buduje tę samą infrastrukturę: multitenancy, płatności, messaging, obserwowalność. I za każdym razem buduje ją w pośpiechu, bo klient chce zobaczyć feature, nie outbox pattern. Więc za każdym razem powstaje ten sam kruchy start.

Co konkretnie znaczy „solidny fundament"

Solidny fundament to nie przymiotnik, to lista decyzji, które podejmuje się zanim napisze się pierwszy business feature. Oto co wbudowujemy w ModularPlatform i dlaczego.

Czyste zależności, egzekwowane mechanicznie. Monolit modularny ma sens tylko wtedy, gdy moduły naprawdę nie sięgają sobie nawzajem do wnętrza. Większość „modularnych" kodów obiecuje to w dokumentacji, a potem nikt tego nie pilnuje — po pół roku wychodzi z tego gąszcz. My egzekwujemy to testami ArchUnitNET: gdy ktoś wprowadzi niedozwoloną zależność między modułami, padnie build, a nie produkcja za rok. Granica pilnowana przez test wytrzymuje. Granica pilnowana przez dobrą wolę — nie.

Durable messaging od początku. Komunikacja między modułami i ze światem zewnętrznym idzie przez Wolverine — outbox, inbox, sagi. To dokładnie ta maszyna, którą w KSeF musiałem dobudowywać ręcznie po incydencie. Gdy masz ją od pierwszego dnia, żadna wiadomość nie zginie po cichu między „zapisałem do DB" a „wysłałem dalej". Te dwie operacje albo obydwie przejdą, albo żadna.

Multitenancy i izolacja danych. Izolacja tenantów przez Postgres row-level security. Oznacza to, że oddzielenia danych klientów nie pilnuje kod aplikacji, który może mieć buga, ale baza danych sama. Gdy programista się pomyli i zapomni w zapytaniu o filtr po tenancie, RLS i tak nie puści go do cudzych danych. To dokładnie ten typ rzeczy, który w PoC odkłada się na „rozwiążemy to później" — i później staje się z tego incydent bezpieczeństwa.

Security i GDPR domyślnie. Crypto-shred do usuwania danych GDPR — gdy klient ma prawo do bycia zapomnianym, usuwamy klucz i dane stają się nieczytelne, zamiast gonić kopie po backupach. Audit log i izolacja idą z tym w parze. Tego nie da się wiarygodnie dokleić; albo jest w fundamencie, albo nie ma.

Płatności. Integracja Stripe w fundamencie, bo płatny produkt potrzebuje rozliczeń — a większość zespołów odkrywa to dopiero gdy ma już klienta i żadnego billingu.

Self-healing i działanie na wielu maszynach. Fundament jest zaprojektowany tak, żeby działał multi-machine i żeby po awarii jednego węzła odnawiał się sam, a nie żeby ktoś o trzeciej w nocy restartował go ręcznie.

Obserwowalność od początku, nie po pierwszej awarii. Strukturyzowane eventy na przejściach stanów, żeby widać było, co gdzie się dzieje. To lekcja z KSeF wpisana w fundament: cichy LogWarning bez alertu to dług, nie monitoring. Pipeline, która utraciła 15 141 dokumentów, jest droga głównie dlatego, że nikt tego nie widział na czas.

Frontend działa na Next.js 15 i React 19, backend to monolit modularny w .NET. Monolit celowo — dla aplikacji read-heavy czysty monolit modularny z egzekwowanymi granicami jest zazwyczaj rozsądniejszy niż mikroserwisy, które dodają złożoność operacyjną, której większość produktów nie potrzebuje.

Dlaczego to oszczędza klientowi czas i pieniądze

To nie jest akademiczne ćwiczenie w czystości kodu. Ma trzy konkretne konsekwencje dla tego, kto nas zatrudni.

Szybszy time-to-market. Nowy produkt nie zaczyna od budowania multitenancy, płatności, messagingu i obserwowalności. To już istnieje i jest sprawdzone. Zaczyna się od razu od tego, co jest w produkcie unikalne. To tygodnie, a nawet miesiące, których nie trzeba wydawać na infrastrukturę, której i tak potrzebuje każdy.

Żaden vendor lock-in. Kod źródłowy zostaje u klienta. ModularPlatform nie jest SaaS, w który klient się zamknie i będzie płacił na zawsze. To fundament, na którym buduje się jego produkt — i ten produkt jest jego. Jeśli zdecyduje kontynuować sam lub z innym zespołem, ma w ręku normalny kod .NET, nie czarną skrzynkę.

Niższy koszt odganiania. To najmniej widoczna pozycja i najdroższa. Gdy produkt wylatuje z PoC na produkcję bez fundamentów, nie płaci się za to od razu. Płaci się za rok, w postaci przestojów, utraty danych, incydentów bezpieczeństwa i refaktorów przechodzących przez całą aplikację. Płaciłem ten rachunek w cudzych projektach wystarczająco często, żeby chcieć oszczędzić go klientom.

Nie chcę przesadzać. ModularPlatform jest wewnętrzny i in progress — wciąż nad nim pracujemy i niektóre części są dalej niż inne. To nie gotowy produkt z klikalnym demo. Ale filozofia za nim jest sprawdzona w realnych projektach, gdzie widziałem, co się dzieje, gdy jej brakuje: zagubione dokumenty, kilkudniowy runtime, security odkładane na „później".

Większość zespołów wypuszcza PoC bez fundamentów i rok go odgania. My idziemy odwrotnie. Najpierw fundament, na którym da się budować, potem reszta. Nie dlatego, że jest to elegantsze, ale dlatego, że wystarczająco wiele razy widziałem, ile kosztuje to drugie podejście.

Masz podobny problem? Napisz do nas.

Umów konsultację